2019-07-08 11:40:52 +00:00
|
|
|
package prog8.optimizer
|
2018-09-15 09:56:17 +00:00
|
|
|
|
2024-03-15 00:04:27 +00:00
|
|
|
import prog8.ast.*
|
2021-02-07 17:37:44 +00:00
|
|
|
import prog8.ast.base.FatalAstException
|
2019-07-08 11:30:28 +00:00
|
|
|
import prog8.ast.expressions.*
|
2022-08-27 11:06:44 +00:00
|
|
|
import prog8.ast.statements.AnonymousScope
|
|
|
|
import prog8.ast.statements.IfElse
|
|
|
|
import prog8.ast.statements.Jump
|
2021-02-07 05:49:51 +00:00
|
|
|
import prog8.ast.walk.AstWalker
|
|
|
|
import prog8.ast.walk.IAstModification
|
2022-07-02 19:38:22 +00:00
|
|
|
import prog8.code.core.*
|
2018-09-25 22:58:02 +00:00
|
|
|
import kotlin.math.abs
|
2019-01-06 07:17:18 +00:00
|
|
|
import kotlin.math.log2
|
2019-08-17 13:28:06 +00:00
|
|
|
import kotlin.math.pow
|
2018-09-15 09:56:17 +00:00
|
|
|
|
2024-03-05 00:31:04 +00:00
|
|
|
class ExpressionSimplifier(private val program: Program, private val options: CompilationOptions, private val errors: IErrorReporter) : AstWalker() {
|
2020-03-21 22:09:18 +00:00
|
|
|
private val powersOfTwo = (1..16).map { (2.0).pow(it) }.toSet()
|
2022-07-24 11:20:38 +00:00
|
|
|
private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet()
|
2020-03-21 17:39:36 +00:00
|
|
|
|
|
|
|
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
|
|
|
|
val mods = mutableListOf<IAstModification>()
|
2019-07-10 00:54:39 +00:00
|
|
|
|
|
|
|
// try to statically convert a literal value into one of the desired type
|
2022-02-10 23:21:40 +00:00
|
|
|
val literal = typecast.expression as? NumericLiteral
|
2020-03-21 22:09:18 +00:00
|
|
|
if (literal != null) {
|
2024-02-04 23:53:18 +00:00
|
|
|
val newLiteral = literal.cast(typecast.type, typecast.implicit)
|
|
|
|
if (newLiteral.isValid && newLiteral.valueOrZero() !== literal) {
|
|
|
|
mods += IAstModification.ReplaceNode(typecast, newLiteral.valueOrZero(), parent)
|
2022-07-13 15:20:33 +00:00
|
|
|
}
|
2019-07-10 00:54:39 +00:00
|
|
|
}
|
|
|
|
|
2020-08-20 16:07:48 +00:00
|
|
|
// remove redundant nested typecasts
|
2020-03-21 17:39:36 +00:00
|
|
|
val subTypecast = typecast.expression as? TypecastExpression
|
2020-03-21 22:09:18 +00:00
|
|
|
if (subTypecast != null) {
|
2020-08-20 16:07:48 +00:00
|
|
|
// remove the sub-typecast if its datatype is larger than the outer typecast
|
|
|
|
if(subTypecast.type largerThan typecast.type) {
|
|
|
|
mods += IAstModification.ReplaceNode(typecast.expression, subTypecast.expression, typecast)
|
|
|
|
}
|
2020-03-21 17:39:36 +00:00
|
|
|
} else {
|
2021-10-14 22:28:23 +00:00
|
|
|
if (typecast.expression.inferType(program) istype typecast.type) {
|
2020-08-20 16:07:48 +00:00
|
|
|
// remove duplicate cast
|
2020-03-21 17:39:36 +00:00
|
|
|
mods += IAstModification.ReplaceNode(typecast, typecast.expression, parent)
|
2020-08-20 16:07:48 +00:00
|
|
|
}
|
2020-03-21 17:39:36 +00:00
|
|
|
}
|
2019-07-09 23:52:04 +00:00
|
|
|
|
2020-03-21 17:39:36 +00:00
|
|
|
return mods
|
|
|
|
}
|
|
|
|
|
2021-12-28 12:56:47 +00:00
|
|
|
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
|
|
|
|
val truepart = ifElse.truepart
|
|
|
|
val elsepart = ifElse.elsepart
|
2021-12-27 14:04:25 +00:00
|
|
|
if(truepart.isNotEmpty() && elsepart.isNotEmpty()) {
|
|
|
|
if(truepart.statements.singleOrNull() is Jump) {
|
|
|
|
return listOf(
|
2021-12-28 12:56:47 +00:00
|
|
|
IAstModification.InsertAfter(ifElse, elsepart, parent as IStatementContainer),
|
|
|
|
IAstModification.ReplaceNode(elsepart, AnonymousScope(mutableListOf(), elsepart.position), ifElse)
|
2021-12-27 14:04:25 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
if(elsepart.statements.singleOrNull() is Jump) {
|
2024-01-05 14:31:45 +00:00
|
|
|
val invertedCondition = invertCondition(ifElse.condition, program)
|
2024-01-05 12:32:16 +00:00
|
|
|
return listOf(
|
|
|
|
IAstModification.ReplaceNode(ifElse.condition, invertedCondition, ifElse),
|
|
|
|
IAstModification.InsertAfter(ifElse, truepart, parent as IStatementContainer),
|
|
|
|
IAstModification.ReplaceNode(elsepart, AnonymousScope(mutableListOf(), elsepart.position), ifElse),
|
|
|
|
IAstModification.ReplaceNode(truepart, elsepart, ifElse)
|
|
|
|
)
|
2021-12-27 14:04:25 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-11 21:43:05 +00:00
|
|
|
|
2024-01-06 20:47:59 +00:00
|
|
|
val booleanCondition = ifElse.condition as? BinaryExpression
|
|
|
|
if(booleanCondition!=null && booleanCondition.operator=="&") {
|
|
|
|
val rightNum = booleanCondition.right as? NumericLiteral
|
|
|
|
if (rightNum!=null && rightNum.type==DataType.UWORD) {
|
|
|
|
if ((rightNum.number.toInt() and 0x00ff) == 0) {
|
|
|
|
// if WORD & $xx00 -> if msb(WORD) & $xx
|
2022-08-11 21:43:05 +00:00
|
|
|
val msb = BuiltinFunctionCall(IdentifierReference(listOf("msb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position)
|
|
|
|
val bytevalue = NumericLiteral(DataType.UBYTE, (rightNum.number.toInt() shr 8).toDouble(), booleanCondition.right.position)
|
|
|
|
return listOf(
|
|
|
|
IAstModification.ReplaceNode(booleanCondition.left, msb, booleanCondition),
|
|
|
|
IAstModification.ReplaceNode(booleanCondition.right, bytevalue, booleanCondition))
|
|
|
|
}
|
2024-01-06 20:47:59 +00:00
|
|
|
else if ((rightNum.number.toInt() and 0xff00) == 0) {
|
|
|
|
// if WORD & $00ff -> if lsb(WORD) & $ff
|
|
|
|
val lsb = BuiltinFunctionCall(IdentifierReference(listOf("lsb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position)
|
|
|
|
val bytevalue = NumericLiteral(DataType.UBYTE, rightNum.number, booleanCondition.right.position)
|
|
|
|
return listOf(
|
|
|
|
IAstModification.ReplaceNode(booleanCondition.left, lsb, booleanCondition),
|
|
|
|
IAstModification.ReplaceNode(booleanCondition.right, bytevalue, booleanCondition))
|
|
|
|
}
|
2022-08-11 21:43:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 14:04:25 +00:00
|
|
|
return noModifications
|
|
|
|
}
|
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
2024-01-04 23:26:56 +00:00
|
|
|
val newExpr = applyAbsorptionLaws(expr)
|
|
|
|
if(newExpr!=null)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent))
|
|
|
|
|
2019-06-20 19:06:51 +00:00
|
|
|
val leftVal = expr.left.constValue(program)
|
|
|
|
val rightVal = expr.right.constValue(program)
|
2018-09-25 20:16:32 +00:00
|
|
|
|
2019-08-14 00:25:27 +00:00
|
|
|
val leftIDt = expr.left.inferType(program)
|
|
|
|
val rightIDt = expr.right.inferType(program)
|
2020-03-21 22:09:18 +00:00
|
|
|
if (!leftIDt.isKnown || !rightIDt.isKnown)
|
2019-08-14 00:25:27 +00:00
|
|
|
throw FatalAstException("can't determine datatype of both expression operands $expr")
|
|
|
|
|
2019-01-11 21:15:05 +00:00
|
|
|
// X + (-A) --> X - A
|
2019-01-13 00:07:31 +00:00
|
|
|
if (expr.operator == "+" && (expr.right as? PrefixExpression)?.operator == "-") {
|
2020-03-21 22:09:18 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(
|
|
|
|
expr,
|
|
|
|
BinaryExpression(expr.left, "-", (expr.right as PrefixExpression).expression, expr.position),
|
|
|
|
parent
|
|
|
|
))
|
2019-01-11 21:15:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// (-A) + X --> X - A
|
2019-01-13 00:07:31 +00:00
|
|
|
if (expr.operator == "+" && (expr.left as? PrefixExpression)?.operator == "-") {
|
2020-03-21 22:09:18 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(
|
|
|
|
expr,
|
|
|
|
BinaryExpression(expr.right, "-", (expr.left as PrefixExpression).expression, expr.position),
|
|
|
|
parent
|
|
|
|
))
|
2019-01-11 21:15:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// X - (-A) --> X + A
|
2019-01-13 00:07:31 +00:00
|
|
|
if (expr.operator == "-" && (expr.right as? PrefixExpression)?.operator == "-") {
|
2020-03-21 22:09:18 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(
|
|
|
|
expr,
|
|
|
|
BinaryExpression(expr.left, "+", (expr.right as PrefixExpression).expression, expr.position),
|
|
|
|
parent
|
|
|
|
))
|
2019-01-11 21:15:05 +00:00
|
|
|
}
|
|
|
|
|
2021-10-12 22:21:38 +00:00
|
|
|
val leftDt = leftIDt.getOr(DataType.UNDEFINED)
|
|
|
|
val rightDt = rightIDt.getOr(DataType.UNDEFINED)
|
2019-01-11 21:15:05 +00:00
|
|
|
|
2019-01-13 00:07:31 +00:00
|
|
|
if (expr.operator == "+" || expr.operator == "-"
|
|
|
|
&& leftVal == null && rightVal == null
|
|
|
|
&& leftDt in NumericDatatypes && rightDt in NumericDatatypes) {
|
|
|
|
val leftBinExpr = expr.left as? BinaryExpression
|
|
|
|
val rightBinExpr = expr.right as? BinaryExpression
|
|
|
|
if (leftBinExpr?.operator == "*") {
|
|
|
|
if (expr.operator == "+") {
|
2020-03-21 22:09:18 +00:00
|
|
|
// Y*X + X -> X*(Y + 1)
|
|
|
|
// X*Y + X -> X*(Y + 1)
|
2019-01-13 00:07:31 +00:00
|
|
|
val x = expr.right
|
|
|
|
val y = determineY(x, leftBinExpr)
|
2020-03-21 22:09:18 +00:00
|
|
|
if (y != null) {
|
2022-02-10 23:21:40 +00:00
|
|
|
val yPlus1 = BinaryExpression(y, "+", NumericLiteral(leftDt, 1.0, y.position), y.position)
|
2024-01-04 23:26:56 +00:00
|
|
|
val replacement = BinaryExpression(x, "*", yPlus1, x.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, replacement, parent))
|
2019-01-13 00:07:31 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Y*X - X -> X*(Y - 1)
|
|
|
|
// X*Y - X -> X*(Y - 1)
|
|
|
|
val x = expr.right
|
|
|
|
val y = determineY(x, leftBinExpr)
|
2020-03-21 22:09:18 +00:00
|
|
|
if (y != null) {
|
2022-02-10 23:21:40 +00:00
|
|
|
val yMinus1 = BinaryExpression(y, "-", NumericLiteral(leftDt, 1.0, y.position), y.position)
|
2024-01-04 23:26:56 +00:00
|
|
|
val replacement = BinaryExpression(x, "*", yMinus1, x.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, replacement, parent))
|
2019-01-13 00:07:31 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
} else if (rightBinExpr?.operator == "*") {
|
|
|
|
if (expr.operator == "+") {
|
2019-01-13 00:07:31 +00:00
|
|
|
// X + Y*X -> X*(Y + 1)
|
|
|
|
// X + X*Y -> X*(Y + 1)
|
|
|
|
val x = expr.left
|
|
|
|
val y = determineY(x, rightBinExpr)
|
2020-03-21 22:09:18 +00:00
|
|
|
if (y != null) {
|
2022-02-10 23:21:40 +00:00
|
|
|
val yPlus1 = BinaryExpression(y, "+", NumericLiteral.optimalInteger(1, y.position), y.position)
|
2024-01-04 23:26:56 +00:00
|
|
|
val replacement = BinaryExpression(x, "*", yPlus1, x.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, replacement, parent))
|
2019-01-13 00:07:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-04 14:49:58 +00:00
|
|
|
// X <= Y-1 ---> X<Y , X >= Y+1 ---> X>Y
|
|
|
|
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
|
|
|
|
val rightExpr = expr.right as? BinaryExpression
|
|
|
|
if(rightExpr!=null && rightExpr.right.constValue(program)?.number==1.0) {
|
|
|
|
if (expr.operator == "<=" && rightExpr.operator == "-") {
|
|
|
|
expr.operator = "<"
|
|
|
|
return listOf(IAstModification.ReplaceNode(rightExpr, rightExpr.left, expr))
|
|
|
|
} else if (expr.operator == ">=" && rightExpr.operator == "+") {
|
|
|
|
expr.operator = ">"
|
|
|
|
return listOf(IAstModification.ReplaceNode(rightExpr, rightExpr.left, expr))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 23:04:52 +00:00
|
|
|
if(leftDt!=DataType.FLOAT && expr.operator == ">=" && rightVal?.number == 1.0) {
|
|
|
|
// for integers: x >= 1 --> x > 0
|
|
|
|
expr.operator = ">"
|
2022-02-10 23:21:40 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral.optimalInteger(0, expr.right.position), expr))
|
2021-11-16 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2023-03-04 14:49:58 +00:00
|
|
|
// for signed integers: X <= -1 => X<0 , X > -1 => X>=0
|
|
|
|
if(leftDt in SignedDatatypes && leftDt!=DataType.FLOAT && rightVal?.number==-1.0) {
|
|
|
|
if(expr.operator=="<=") {
|
|
|
|
expr.operator = "<"
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral(rightDt, 0.0, expr.right.position), expr))
|
|
|
|
} else if(expr.operator==">") {
|
|
|
|
expr.operator = ">="
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral(rightDt, 0.0, expr.right.position), expr))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-12 19:37:57 +00:00
|
|
|
if (leftDt == DataType.UBYTE || leftDt == DataType.UWORD) {
|
|
|
|
if(expr.operator == ">=" && rightVal?.number == 0.0) {
|
2020-06-03 23:43:37 +00:00
|
|
|
// unsigned >= 0 --> true
|
2022-02-10 23:21:40 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(true, expr.position), parent))
|
2020-06-03 23:43:37 +00:00
|
|
|
}
|
2022-12-12 19:37:57 +00:00
|
|
|
else if(expr.operator == ">" && rightVal?.number == 0.0) {
|
|
|
|
// unsigned > 0 --> unsigned != 0
|
|
|
|
return listOf(IAstModification.SetExpression({expr.operator="!="}, expr, parent))
|
|
|
|
}
|
2020-06-03 23:43:37 +00:00
|
|
|
}
|
|
|
|
|
2021-11-16 23:04:52 +00:00
|
|
|
if(leftDt!=DataType.FLOAT && expr.operator == "<" && rightVal?.number == 1.0) {
|
|
|
|
// for integers: x < 1 --> x <= 0
|
|
|
|
expr.operator = "<="
|
2022-02-10 23:21:40 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, NumericLiteral.optimalInteger(0, expr.right.position), expr))
|
2021-11-16 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2022-12-12 19:37:57 +00:00
|
|
|
if (leftDt == DataType.UBYTE || leftDt == DataType.UWORD) {
|
|
|
|
if(expr.operator == "<" && rightVal?.number == 0.0) {
|
2020-06-03 23:43:37 +00:00
|
|
|
// unsigned < 0 --> false
|
2022-02-10 23:21:40 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(false, expr.position), parent))
|
2020-06-03 23:43:37 +00:00
|
|
|
}
|
2022-12-12 19:37:57 +00:00
|
|
|
else if(expr.operator == "<=" && rightVal?.number == 0.0) {
|
|
|
|
// unsigned <= 0 --> unsigned==0
|
|
|
|
return listOf(IAstModification.SetExpression({expr.operator="=="}, expr, parent))
|
|
|
|
}
|
2020-06-03 23:43:37 +00:00
|
|
|
}
|
|
|
|
|
2024-03-05 00:31:04 +00:00
|
|
|
// optimize boolean constant comparisons
|
|
|
|
if(expr.operator=="==") {
|
|
|
|
if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) {
|
|
|
|
if(rightVal?.asBooleanValue==true)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
|
|
|
|
else
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent))
|
|
|
|
}
|
|
|
|
if (rightVal?.number == 1.0) {
|
|
|
|
if (options.strictBool) {
|
|
|
|
if (rightDt != leftDt) {
|
|
|
|
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
|
|
|
|
}
|
|
|
|
else if (rightVal?.number == 0.0) {
|
|
|
|
if (options.strictBool) {
|
|
|
|
if (rightDt != leftDt) {
|
|
|
|
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (expr.operator=="!=") {
|
|
|
|
if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) {
|
2024-03-13 19:23:42 +00:00
|
|
|
val rightConstBool = rightVal?.asBooleanValue
|
|
|
|
if(rightConstBool!=null) {
|
|
|
|
return if (rightConstBool)
|
|
|
|
listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent))
|
|
|
|
else
|
|
|
|
listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
|
|
|
|
}
|
2024-03-05 00:31:04 +00:00
|
|
|
}
|
|
|
|
if (rightVal?.number == 1.0) {
|
|
|
|
if(options.strictBool) {
|
|
|
|
if(rightDt!=leftDt) {
|
|
|
|
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rightVal?.number == 0.0) {
|
|
|
|
if(options.strictBool) {
|
|
|
|
if(rightDt!=leftDt) {
|
|
|
|
val right = NumericLiteral(leftDt, rightVal.number, rightVal.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr.right, right, expr))
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
|
|
|
|
}
|
|
|
|
}
|
2024-02-04 23:53:18 +00:00
|
|
|
|
2024-03-05 00:31:04 +00:00
|
|
|
if(expr.operator in arrayOf("and", "or", "xor")) {
|
|
|
|
if(leftVal!=null) {
|
|
|
|
val result = if(leftVal.asBooleanValue) {
|
|
|
|
when(expr.operator) {
|
|
|
|
"and" -> expr.right
|
|
|
|
"or" -> NumericLiteral.fromBoolean(true, expr.position)
|
|
|
|
"xor" -> PrefixExpression("not", expr.right, expr.position)
|
|
|
|
else -> throw FatalAstException("weird op")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
when(expr.operator) {
|
|
|
|
"and" -> NumericLiteral.fromBoolean(false, expr.position)
|
|
|
|
"or" -> expr.right
|
|
|
|
"xor" -> expr.right
|
|
|
|
else -> throw FatalAstException("weird op")
|
2024-02-04 23:53:18 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-05 00:31:04 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(expr, result, parent))
|
|
|
|
}
|
|
|
|
else if(rightVal!=null) {
|
|
|
|
val result = if(rightVal.asBooleanValue) {
|
|
|
|
when(expr.operator) {
|
|
|
|
"and" -> expr.left
|
|
|
|
"or" -> NumericLiteral.fromBoolean(true, expr.position)
|
|
|
|
"xor" -> PrefixExpression("not", expr.left, expr.position)
|
|
|
|
else -> throw FatalAstException("weird op")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
when(expr.operator) {
|
|
|
|
"and" -> NumericLiteral.fromBoolean(false, expr.position)
|
|
|
|
"or" -> expr.left
|
|
|
|
"xor" -> expr.left
|
|
|
|
else -> throw FatalAstException("weird op")
|
2024-02-04 23:53:18 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-05 00:31:04 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(expr, result, parent))
|
2024-02-04 23:53:18 +00:00
|
|
|
}
|
2022-12-29 15:56:20 +00:00
|
|
|
}
|
|
|
|
|
2020-06-04 18:22:37 +00:00
|
|
|
// simplify when a term is constant and directly determines the outcome
|
2022-02-10 23:21:40 +00:00
|
|
|
val constFalse = NumericLiteral.fromBoolean(false, expr.position)
|
2024-01-04 23:26:56 +00:00
|
|
|
val newExpr2 = when (expr.operator) {
|
2021-11-18 01:51:42 +00:00
|
|
|
"|" -> {
|
|
|
|
when {
|
|
|
|
leftVal?.number==0.0 -> expr.right
|
|
|
|
rightVal?.number==0.0 -> expr.left
|
2022-02-10 23:21:40 +00:00
|
|
|
rightIDt.isBytes && rightVal?.number==255.0 -> NumericLiteral(DataType.UBYTE, 255.0, rightVal.position)
|
|
|
|
rightIDt.isWords && rightVal?.number==65535.0 -> NumericLiteral(DataType.UWORD, 65535.0, rightVal.position)
|
|
|
|
leftIDt.isBytes && leftVal?.number==255.0 -> NumericLiteral(DataType.UBYTE, 255.0, leftVal.position)
|
|
|
|
leftIDt.isWords && leftVal?.number==65535.0 -> NumericLiteral(DataType.UWORD, 65535.0, leftVal.position)
|
2021-11-18 01:51:42 +00:00
|
|
|
else -> null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"^" -> {
|
|
|
|
when {
|
|
|
|
leftVal?.number==0.0 -> expr.right
|
|
|
|
rightVal?.number==0.0 -> expr.left
|
|
|
|
rightIDt.isBytes && rightVal?.number==255.0 -> PrefixExpression("~", expr.left, expr.left.position)
|
|
|
|
rightIDt.isWords && rightVal?.number==65535.0 -> PrefixExpression("~", expr.left, expr.left.position)
|
|
|
|
leftIDt.isBytes && leftVal?.number==255.0 -> PrefixExpression("~", expr.right, expr.right.position)
|
|
|
|
leftIDt.isWords && leftVal?.number==65535.0 -> PrefixExpression("~", expr.right, expr.right.position)
|
|
|
|
else -> null
|
2021-11-16 22:52:30 +00:00
|
|
|
}
|
2018-09-25 20:16:32 +00:00
|
|
|
}
|
|
|
|
"&" -> {
|
2021-11-18 01:51:42 +00:00
|
|
|
when {
|
|
|
|
leftVal?.number==0.0 -> constFalse
|
|
|
|
rightVal?.number==0.0 -> constFalse
|
|
|
|
rightIDt.isBytes && rightVal?.number==255.0 -> expr.left
|
|
|
|
rightIDt.isWords && rightVal?.number==65535.0 -> expr.left
|
|
|
|
leftIDt.isBytes && leftVal?.number==255.0 -> expr.right
|
|
|
|
leftIDt.isWords && leftVal?.number==65535.0 -> expr.right
|
|
|
|
else -> null
|
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
}
|
|
|
|
"*" -> optimizeMultiplication(expr, leftVal, rightVal)
|
|
|
|
"/" -> optimizeDivision(expr, leftVal, rightVal)
|
|
|
|
"+" -> optimizeAdd(expr, leftVal, rightVal)
|
|
|
|
"-" -> optimizeSub(expr, leftVal, rightVal)
|
|
|
|
"%" -> optimizeRemainder(expr, leftVal, rightVal)
|
|
|
|
">>" -> optimizeShiftRight(expr, rightVal)
|
|
|
|
"<<" -> optimizeShiftLeft(expr, rightVal)
|
|
|
|
else -> null
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
|
2022-07-11 13:46:14 +00:00
|
|
|
if(rightVal!=null && leftDt==DataType.BOOL) {
|
2024-01-05 12:32:16 +00:00
|
|
|
// boolean compare against a number -> just keep the boolean, no compare
|
|
|
|
if(expr.operator=="==" || expr.operator=="!=") {
|
|
|
|
val test = if (expr.operator == "==") rightVal.asBooleanValue else !rightVal.asBooleanValue
|
|
|
|
return if (test) {
|
|
|
|
listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
|
|
|
|
} else {
|
2024-01-05 14:31:45 +00:00
|
|
|
listOf(IAstModification.ReplaceNode(expr, invertCondition(expr.left, program), parent))
|
2022-07-11 13:46:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-04 23:26:56 +00:00
|
|
|
if(newExpr2 != null)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, newExpr2, parent))
|
2020-03-21 22:09:18 +00:00
|
|
|
|
2024-01-06 20:47:59 +00:00
|
|
|
if (rightVal!=null && (expr.operator == "==" || expr.operator == "!=")) {
|
|
|
|
val bitwise = expr.left as? BinaryExpression
|
|
|
|
if(bitwise!=null && bitwise.operator=="&" && bitwise.inferType(program).isWords) {
|
|
|
|
val andNum = (bitwise.right as? NumericLiteral)?.number?.toInt()
|
|
|
|
if (andNum!=null) {
|
|
|
|
if ((andNum and 0x00ff) == 0) {
|
|
|
|
// (WORD & $xx00)==y -> (msb(WORD) & $xx)==y
|
|
|
|
val msb = BuiltinFunctionCall(IdentifierReference(listOf("msb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position)
|
|
|
|
val bytevalue = NumericLiteral(DataType.UBYTE, (andNum shr 8).toDouble(), bitwise.right.position)
|
|
|
|
val rightvalByte = NumericLiteral(DataType.UBYTE, (rightVal.number.toInt() shr 8).toDouble(), rightVal.position)
|
|
|
|
return listOf(
|
|
|
|
IAstModification.ReplaceNode(bitwise.left, msb, bitwise),
|
|
|
|
IAstModification.ReplaceNode(bitwise.right, bytevalue, bitwise),
|
|
|
|
IAstModification.ReplaceNode(expr.right, rightvalByte, expr)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else if((andNum and 0xff00) == 0) {
|
|
|
|
// (WORD & $00xx)==y -> (lsb(WORD) & $xx)==y
|
|
|
|
val lsb = BuiltinFunctionCall(IdentifierReference(listOf("lsb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position)
|
|
|
|
val bytevalue = NumericLiteral(DataType.UBYTE, andNum.toDouble(), bitwise.right.position)
|
|
|
|
val rightvalByte = NumericLiteral(DataType.UBYTE, (rightVal.number.toInt() and 255).toDouble(), rightVal.position)
|
|
|
|
return listOf(
|
|
|
|
IAstModification.ReplaceNode(bitwise.left, lsb, bitwise),
|
|
|
|
IAstModification.ReplaceNode(bitwise.right, bytevalue, bitwise),
|
|
|
|
IAstModification.ReplaceNode(expr.right, rightvalByte, expr)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-14 00:54:29 +00:00
|
|
|
return noModifications
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
|
2024-01-05 14:31:45 +00:00
|
|
|
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
|
|
|
if(expr.operator=="not") {
|
|
|
|
// not X <compare> Y -> X <invertedcompare> Y
|
|
|
|
val binExpr = expr.expression as? BinaryExpression
|
|
|
|
if(binExpr!=null) {
|
|
|
|
val invertedOperator = invertedComparisonOperator(binExpr.operator)
|
|
|
|
if(invertedOperator!=null) {
|
|
|
|
val inverted = BinaryExpression(binExpr.left, invertedOperator, binExpr.right, binExpr.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(expr, inverted, parent))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return noModifications
|
|
|
|
}
|
|
|
|
|
2024-01-04 23:26:56 +00:00
|
|
|
private fun applyAbsorptionLaws(expr: BinaryExpression): Expression? {
|
2024-03-15 00:04:27 +00:00
|
|
|
// NOTE: only when the terms are not function calls!!!
|
|
|
|
if(expr.left is IFunctionCall || expr.right is IFunctionCall)
|
|
|
|
return null
|
2024-01-04 23:26:56 +00:00
|
|
|
val rightB = expr.right as? BinaryExpression
|
|
|
|
if(rightB!=null) {
|
2024-03-15 00:04:27 +00:00
|
|
|
if(rightB.left is IFunctionCall || rightB.right is IFunctionCall)
|
|
|
|
return null
|
2024-01-04 23:26:56 +00:00
|
|
|
// absorption laws: a or (a and b) --> a, a and (a or b) --> a
|
|
|
|
if(expr.operator=="or" && rightB.operator=="and") {
|
|
|
|
if(expr.left isSameAs rightB.left || expr.left isSameAs rightB.right) {
|
|
|
|
return expr.left
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(expr.operator=="and" && rightB.operator=="or") {
|
|
|
|
if(expr.left isSameAs rightB.left || expr.left isSameAs rightB.right) {
|
|
|
|
return expr.left
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 19:58:28 +00:00
|
|
|
else if(expr.operator=="or" && rightB.operator=="or") {
|
|
|
|
if(expr.left isSameAs rightB.left || expr.left isSameAs rightB.right) {
|
|
|
|
// a or (a or b) -> a or b
|
|
|
|
return expr.right
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(expr.operator=="and" && rightB.operator=="and") {
|
|
|
|
if(expr.left isSameAs rightB.left || expr.left isSameAs rightB.right) {
|
|
|
|
// a and (a and b) -> a and b
|
|
|
|
return expr.right
|
|
|
|
}
|
|
|
|
}
|
2024-01-04 23:26:56 +00:00
|
|
|
}
|
|
|
|
val leftB = expr.left as? BinaryExpression
|
|
|
|
if(leftB!=null) {
|
2024-03-15 00:04:27 +00:00
|
|
|
if(leftB.left is IFunctionCall || leftB.right is IFunctionCall)
|
|
|
|
return null
|
2024-01-04 23:26:56 +00:00
|
|
|
// absorption laws: (a and b) or a --> a, (a or b) and a --> a
|
|
|
|
if(expr.operator=="or" && leftB.operator=="and") {
|
2024-02-14 19:58:28 +00:00
|
|
|
if(expr.right isSameAs leftB.left || expr.right isSameAs leftB.right) {
|
2024-01-04 23:26:56 +00:00
|
|
|
return expr.right
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(expr.operator=="and" && leftB.operator=="or") {
|
|
|
|
if(expr.right isSameAs leftB.left || expr.right isSameAs leftB.right) {
|
|
|
|
return expr.right
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 19:58:28 +00:00
|
|
|
else if(expr.operator=="or" && leftB.operator=="or") {
|
|
|
|
if(expr.right isSameAs leftB.left || expr.right isSameAs leftB.right) {
|
|
|
|
// (a or b) or a -> a or b
|
|
|
|
return expr.left
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(expr.operator=="and" && leftB.operator=="and") {
|
|
|
|
if(expr.right isSameAs leftB.left || expr.right isSameAs leftB.right) {
|
|
|
|
// (a and b) or a -> a and b
|
|
|
|
return expr.left
|
|
|
|
}
|
|
|
|
}
|
2024-01-04 23:26:56 +00:00
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2022-01-07 20:02:37 +00:00
|
|
|
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
2021-12-28 12:56:47 +00:00
|
|
|
if(functionCallExpr.target.nameInSource == listOf("lsb")) {
|
2022-04-13 21:23:59 +00:00
|
|
|
if(functionCallExpr.args.isEmpty())
|
|
|
|
return noModifications
|
2021-12-28 12:56:47 +00:00
|
|
|
val arg = functionCallExpr.args[0]
|
2020-09-09 19:37:56 +00:00
|
|
|
if(arg is TypecastExpression) {
|
|
|
|
val valueDt = arg.expression.inferType(program)
|
2024-01-10 22:57:44 +00:00
|
|
|
if (valueDt istype DataType.UBYTE) {
|
|
|
|
// useless lsb() of ubyte value
|
2021-12-28 12:56:47 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr, arg.expression, parent))
|
2020-09-09 19:37:56 +00:00
|
|
|
}
|
2024-01-10 22:57:44 +00:00
|
|
|
else if (valueDt istype DataType.BYTE) {
|
|
|
|
// useless lsb() of byte value, but as lsb() returns unsigned, we have to cast now.
|
|
|
|
val cast = TypecastExpression(arg.expression, DataType.UBYTE, true, arg.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent))
|
|
|
|
}
|
2020-09-09 19:37:56 +00:00
|
|
|
} else {
|
2022-07-02 19:38:22 +00:00
|
|
|
if(arg is IdentifierReference && arg.nameInSource.size==2
|
|
|
|
&& arg.nameInSource[0]=="cx16" && arg.nameInSource[1].uppercase() in RegisterOrPair.names) {
|
|
|
|
// lsb(cx16.r0) -> cx16.r0L
|
|
|
|
val highReg = IdentifierReference(listOf("cx16", arg.nameInSource[1]+'L'), arg.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr, highReg, parent))
|
|
|
|
}
|
2020-09-09 19:37:56 +00:00
|
|
|
val argDt = arg.inferType(program)
|
2024-01-10 22:57:44 +00:00
|
|
|
if (argDt istype DataType.UBYTE) {
|
2020-09-09 19:37:56 +00:00
|
|
|
// useless lsb() of byte value
|
2021-12-28 12:56:47 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr, arg, parent))
|
2020-09-09 19:37:56 +00:00
|
|
|
}
|
2024-01-10 22:57:44 +00:00
|
|
|
else if (argDt istype DataType.BYTE) {
|
|
|
|
// useless lsb() of byte value, but as lsb() returns unsigned, we have to cast now.
|
|
|
|
val cast = TypecastExpression(arg, DataType.UBYTE, true, arg.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent))
|
|
|
|
}
|
2020-09-09 19:37:56 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-28 12:56:47 +00:00
|
|
|
else if(functionCallExpr.target.nameInSource == listOf("msb")) {
|
2022-04-13 21:23:59 +00:00
|
|
|
if(functionCallExpr.args.isEmpty())
|
|
|
|
return noModifications
|
2021-12-28 12:56:47 +00:00
|
|
|
val arg = functionCallExpr.args[0]
|
2020-09-09 19:37:56 +00:00
|
|
|
if(arg is TypecastExpression) {
|
|
|
|
val valueDt = arg.expression.inferType(program)
|
2021-10-14 22:28:23 +00:00
|
|
|
if (valueDt istype DataType.BYTE || valueDt istype DataType.UBYTE) {
|
2021-10-10 21:35:02 +00:00
|
|
|
// useless msb() of byte value that was typecasted to word, replace with 0
|
2020-09-09 19:37:56 +00:00
|
|
|
return listOf(IAstModification.ReplaceNode(
|
2021-12-28 12:56:47 +00:00
|
|
|
functionCallExpr,
|
2022-02-10 23:21:40 +00:00
|
|
|
NumericLiteral(valueDt.getOr(DataType.UBYTE), 0.0, arg.expression.position),
|
2020-09-09 19:37:56 +00:00
|
|
|
parent))
|
|
|
|
}
|
|
|
|
} else {
|
2022-07-02 19:38:22 +00:00
|
|
|
if(arg is IdentifierReference && arg.nameInSource.size==2
|
|
|
|
&& arg.nameInSource[0]=="cx16" && arg.nameInSource[1].uppercase() in RegisterOrPair.names) {
|
|
|
|
// msb(cx16.r0) -> cx16.r0H
|
|
|
|
val highReg = IdentifierReference(listOf("cx16", arg.nameInSource[1]+'H'), arg.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr, highReg, parent))
|
|
|
|
}
|
2020-09-09 19:37:56 +00:00
|
|
|
val argDt = arg.inferType(program)
|
2021-10-14 22:28:23 +00:00
|
|
|
if (argDt istype DataType.BYTE || argDt istype DataType.UBYTE) {
|
2020-09-09 19:37:56 +00:00
|
|
|
// useless msb() of byte value, replace with 0
|
|
|
|
return listOf(IAstModification.ReplaceNode(
|
2021-12-28 12:56:47 +00:00
|
|
|
functionCallExpr,
|
2022-02-10 23:21:40 +00:00
|
|
|
NumericLiteral(argDt.getOr(DataType.UBYTE), 0.0, arg.position),
|
2020-09-09 19:37:56 +00:00
|
|
|
parent))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-11 20:51:09 +00:00
|
|
|
if(functionCallExpr.target.nameInSource == listOf("mkword")) {
|
|
|
|
if(functionCallExpr.args[0].constValue(program)?.number==0.0) {
|
|
|
|
// just cast the lsb to uword
|
|
|
|
val cast = TypecastExpression(functionCallExpr.args[1], DataType.UWORD, true, functionCallExpr.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent))
|
|
|
|
}
|
|
|
|
}
|
2024-01-05 23:04:15 +00:00
|
|
|
else if(functionCallExpr.target.nameInSource == listOf("string", "contains")) {
|
|
|
|
val target = (functionCallExpr.args[0] as? IdentifierReference)?.targetVarDecl(program)
|
|
|
|
if(target?.value is StringLiteral) {
|
|
|
|
errors.info("for actual strings, use a regular containment check instead: 'char in string'", functionCallExpr.position)
|
|
|
|
val contains = ContainmentCheck(functionCallExpr.args[1], functionCallExpr.args[0], functionCallExpr.position)
|
|
|
|
return listOf(IAstModification.ReplaceNode(functionCallExpr as Node, contains, parent))
|
|
|
|
}
|
|
|
|
}
|
2022-08-11 20:51:09 +00:00
|
|
|
|
2020-09-09 19:37:56 +00:00
|
|
|
return noModifications
|
|
|
|
}
|
|
|
|
|
2019-07-17 00:27:13 +00:00
|
|
|
private fun determineY(x: Expression, subBinExpr: BinaryExpression): Expression? {
|
2019-01-13 00:07:31 +00:00
|
|
|
return when {
|
2019-06-23 13:43:52 +00:00
|
|
|
subBinExpr.left isSameAs x -> subBinExpr.right
|
|
|
|
subBinExpr.right isSameAs x -> subBinExpr.left
|
2019-01-13 00:07:31 +00:00
|
|
|
else -> null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun optimizeAdd(expr: BinaryExpression, leftVal: NumericLiteral?, rightVal: NumericLiteral?): Expression? {
|
2020-03-31 21:52:46 +00:00
|
|
|
if(expr.left.isSameAs(expr.right)) {
|
|
|
|
// optimize X+X into X *2
|
|
|
|
expr.operator = "*"
|
2022-02-10 23:21:40 +00:00
|
|
|
expr.right = NumericLiteral.optimalInteger(2, expr.right.position)
|
2020-03-31 21:52:46 +00:00
|
|
|
expr.right.linkParents(expr)
|
|
|
|
return expr
|
|
|
|
}
|
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
if (leftVal == null && rightVal == null)
|
|
|
|
return null
|
2018-09-25 22:58:02 +00:00
|
|
|
|
2020-12-14 20:37:40 +00:00
|
|
|
val (expr2, _, rightVal2) = reorderAssociativeWithConstant(expr, leftVal)
|
2020-03-21 22:09:18 +00:00
|
|
|
if (rightVal2 != null) {
|
2018-09-25 22:58:02 +00:00
|
|
|
// right value is a constant, see if we can optimize
|
2022-02-10 23:21:40 +00:00
|
|
|
val rightConst: NumericLiteral = rightVal2
|
2021-11-16 22:52:30 +00:00
|
|
|
when (rightConst.number) {
|
2018-09-25 22:58:02 +00:00
|
|
|
0.0 -> {
|
|
|
|
// left
|
2020-03-21 22:09:18 +00:00
|
|
|
return expr2.left
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// no need to check for left val constant (because of associativity)
|
|
|
|
|
2021-11-16 22:52:30 +00:00
|
|
|
val rnum = rightVal?.number
|
2020-10-19 20:51:18 +00:00
|
|
|
if(rnum!=null && rnum<0.0) {
|
|
|
|
expr.operator = "-"
|
2022-02-10 23:21:40 +00:00
|
|
|
expr.right = NumericLiteral(rightVal.type, -rnum, rightVal.position)
|
2020-10-19 20:51:18 +00:00
|
|
|
return expr
|
|
|
|
}
|
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun optimizeSub(expr: BinaryExpression, leftVal: NumericLiteral?, rightVal: NumericLiteral?): Expression? {
|
2020-03-31 21:52:46 +00:00
|
|
|
if(expr.left.isSameAs(expr.right)) {
|
|
|
|
// optimize X-X into 0
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral.optimalInteger(0, expr.position)
|
2020-03-31 21:52:46 +00:00
|
|
|
}
|
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
if (leftVal == null && rightVal == null)
|
|
|
|
return null
|
2018-09-25 22:58:02 +00:00
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
if (rightVal != null) {
|
2018-09-25 22:58:02 +00:00
|
|
|
// right value is a constant, see if we can optimize
|
2021-11-16 22:52:30 +00:00
|
|
|
val rnum = rightVal.number
|
2020-10-20 15:52:55 +00:00
|
|
|
if (rnum == 0.0) {
|
|
|
|
// left
|
|
|
|
return expr.left
|
|
|
|
}
|
|
|
|
|
|
|
|
if(rnum<0.0) {
|
|
|
|
expr.operator = "+"
|
2022-02-10 23:21:40 +00:00
|
|
|
expr.right = NumericLiteral(rightVal.type, -rnum, rightVal.position)
|
2020-10-20 15:52:55 +00:00
|
|
|
return expr
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
if (leftVal != null) {
|
2018-09-25 22:58:02 +00:00
|
|
|
// left value is a constant, see if we can optimize
|
2021-11-16 22:52:30 +00:00
|
|
|
when (leftVal.number) {
|
2018-09-25 22:58:02 +00:00
|
|
|
0.0 -> {
|
|
|
|
// -right
|
|
|
|
return PrefixExpression("-", expr.right, expr.position)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-19 20:51:18 +00:00
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun optimizeRemainder(expr: BinaryExpression, leftVal: NumericLiteral?, rightVal: NumericLiteral?): Expression? {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (leftVal == null && rightVal == null)
|
|
|
|
return null
|
2019-01-11 19:24:36 +00:00
|
|
|
|
|
|
|
// simplify assignments A = B <operator> C
|
|
|
|
|
2019-07-14 22:26:06 +00:00
|
|
|
val cv = rightVal?.number?.toInt()?.toDouble()
|
2020-03-21 22:09:18 +00:00
|
|
|
when (expr.operator) {
|
2019-01-11 19:24:36 +00:00
|
|
|
"%" -> {
|
|
|
|
if (cv == 1.0) {
|
2020-10-30 15:26:19 +00:00
|
|
|
val idt = expr.inferType(program)
|
|
|
|
if(!idt.isKnown)
|
|
|
|
throw FatalAstException("unknown dt")
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral(idt.getOr(DataType.UNDEFINED), 0.0, expr.position)
|
2021-04-08 20:21:16 +00:00
|
|
|
} else if (cv in powersOfTwo) {
|
2019-01-11 19:24:36 +00:00
|
|
|
expr.operator = "&"
|
2022-02-10 23:21:40 +00:00
|
|
|
expr.right = NumericLiteral.optimalInteger(cv!!.toInt()-1, expr.position)
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2019-01-11 19:24:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2019-01-11 19:24:36 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun optimizeDivision(expr: BinaryExpression, leftVal: NumericLiteral?, rightVal: NumericLiteral?): Expression? {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (leftVal == null && rightVal == null)
|
|
|
|
return null
|
2018-09-25 22:58:02 +00:00
|
|
|
|
2019-08-17 13:28:06 +00:00
|
|
|
// cannot shuffle assiciativity with division!
|
2020-03-21 22:09:18 +00:00
|
|
|
if (rightVal != null) {
|
2018-09-25 22:58:02 +00:00
|
|
|
// right value is a constant, see if we can optimize
|
2022-02-10 23:21:40 +00:00
|
|
|
val rightConst: NumericLiteral = rightVal
|
2021-11-16 22:52:30 +00:00
|
|
|
val cv = rightConst.number
|
2019-08-14 00:25:27 +00:00
|
|
|
val leftIDt = expr.left.inferType(program)
|
2020-03-21 22:09:18 +00:00
|
|
|
if (!leftIDt.isKnown)
|
|
|
|
return null
|
2021-10-12 22:21:38 +00:00
|
|
|
val leftDt = leftIDt.getOr(DataType.UNDEFINED)
|
2020-03-21 22:09:18 +00:00
|
|
|
when (cv) {
|
2018-09-25 22:58:02 +00:00
|
|
|
-1.0 -> {
|
2019-01-09 21:01:47 +00:00
|
|
|
// '/' -> -left
|
|
|
|
if (expr.operator == "/") {
|
|
|
|
return PrefixExpression("-", expr.left, expr.position)
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
1.0 -> {
|
2019-01-09 21:01:47 +00:00
|
|
|
// '/' -> left
|
|
|
|
if (expr.operator == "/") {
|
|
|
|
return expr.left
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
2024-01-06 23:01:00 +00:00
|
|
|
256.0 -> {
|
|
|
|
when(leftDt) {
|
|
|
|
DataType.UBYTE -> return NumericLiteral(DataType.UBYTE, 0.0, expr.position)
|
|
|
|
DataType.BYTE -> return null // is either 0 or -1 we cannot tell here
|
|
|
|
DataType.UWORD, DataType.WORD -> {
|
|
|
|
// just use: msb(value) as type
|
|
|
|
val msb = BuiltinFunctionCall(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position)
|
|
|
|
return if(leftDt==DataType.WORD)
|
|
|
|
TypecastExpression(msb, DataType.BYTE, true, expr.position)
|
|
|
|
else
|
|
|
|
TypecastExpression(msb, DataType.UWORD, true, expr.position)
|
|
|
|
}
|
|
|
|
else -> return null
|
|
|
|
}
|
|
|
|
}
|
2019-08-17 13:28:06 +00:00
|
|
|
in powersOfTwo -> {
|
2022-07-24 10:21:10 +00:00
|
|
|
if (leftDt==DataType.UBYTE || leftDt==DataType.UWORD) {
|
2022-07-24 11:20:38 +00:00
|
|
|
// Unsigned number divided by a power of two => shift right
|
2024-04-10 20:04:03 +00:00
|
|
|
// Signed number can't simply be bitshifted in this case (due to rounding issues for negative values),
|
2022-07-24 11:20:38 +00:00
|
|
|
// so we leave that as is and let the code generator deal with it.
|
2019-01-11 19:24:36 +00:00
|
|
|
val numshifts = log2(cv).toInt()
|
2022-02-10 23:21:40 +00:00
|
|
|
return BinaryExpression(expr.left, ">>", NumericLiteral.optimalInteger(numshifts, expr.position), expr.position)
|
2019-01-06 07:17:18 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
|
2019-01-06 14:26:08 +00:00
|
|
|
if (leftDt == DataType.UBYTE) {
|
2021-11-16 22:52:30 +00:00
|
|
|
if (abs(rightConst.number) >= 256.0) {
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral(DataType.UBYTE, 0.0, expr.position)
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
} else if (leftDt == DataType.UWORD) {
|
2021-11-16 22:52:30 +00:00
|
|
|
if (abs(rightConst.number) >= 65536.0) {
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral(DataType.UBYTE, 0.0, expr.position)
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
if (leftVal != null) {
|
2018-09-25 22:58:02 +00:00
|
|
|
// left value is a constant, see if we can optimize
|
2021-11-16 22:52:30 +00:00
|
|
|
when (leftVal.number) {
|
2018-09-25 22:58:02 +00:00
|
|
|
0.0 -> {
|
|
|
|
// 0
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral(leftVal.type, 0.0, expr.position)
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun optimizeMultiplication(expr: BinaryExpression, leftVal: NumericLiteral?, rightVal: NumericLiteral?): Expression? {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (leftVal == null && rightVal == null)
|
|
|
|
return null
|
2018-09-25 22:58:02 +00:00
|
|
|
|
2020-12-14 20:37:40 +00:00
|
|
|
val (expr2, _, rightVal2) = reorderAssociativeWithConstant(expr, leftVal)
|
2020-03-21 22:09:18 +00:00
|
|
|
if (rightVal2 != null) {
|
2018-09-25 22:58:02 +00:00
|
|
|
// right value is a constant, see if we can optimize
|
2020-03-21 22:09:18 +00:00
|
|
|
val leftValue: Expression = expr2.left
|
2022-02-10 23:21:40 +00:00
|
|
|
val rightConst: NumericLiteral = rightVal2
|
2021-11-16 22:52:30 +00:00
|
|
|
when (val cv = rightConst.number) {
|
2018-09-25 22:58:02 +00:00
|
|
|
-1.0 -> {
|
|
|
|
// -left
|
|
|
|
return PrefixExpression("-", leftValue, expr.position)
|
|
|
|
}
|
|
|
|
0.0 -> {
|
|
|
|
// 0
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral(rightConst.type, 0.0, expr.position)
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
|
|
|
1.0 -> {
|
|
|
|
// left
|
2020-03-21 22:09:18 +00:00
|
|
|
return expr2.left
|
2018-09-25 22:58:02 +00:00
|
|
|
}
|
2019-08-17 16:38:28 +00:00
|
|
|
in powersOfTwo -> {
|
2021-10-10 22:01:26 +00:00
|
|
|
if (leftValue.inferType(program).isInteger) {
|
2019-01-06 07:17:18 +00:00
|
|
|
// times a power of two => shift left
|
2019-01-11 01:35:57 +00:00
|
|
|
val numshifts = log2(cv).toInt()
|
2022-02-10 23:21:40 +00:00
|
|
|
return BinaryExpression(expr2.left, "<<", NumericLiteral.optimalInteger(numshifts, expr.position), expr.position)
|
2019-01-06 07:17:18 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-24 11:20:38 +00:00
|
|
|
in negativePowersOfTwo -> {
|
|
|
|
if (leftValue.inferType(program).isInteger) {
|
|
|
|
// times a negative power of two => negate, then shift
|
|
|
|
val numshifts = log2(-cv).toInt()
|
|
|
|
val negation = PrefixExpression("-", expr2.left, expr.position)
|
|
|
|
return BinaryExpression(negation, "<<", NumericLiteral.optimalInteger(numshifts, expr.position), expr.position)
|
|
|
|
}
|
|
|
|
}
|
2018-09-25 20:16:32 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-25 22:58:02 +00:00
|
|
|
// no need to check for left val constant (because of associativity)
|
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2018-09-25 20:16:32 +00:00
|
|
|
}
|
2019-08-17 13:28:06 +00:00
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun optimizeShiftLeft(expr: BinaryExpression, amountLv: NumericLiteral?): Expression? {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (amountLv == null)
|
|
|
|
return null
|
2019-08-17 13:28:06 +00:00
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
val amount = amountLv.number.toInt()
|
|
|
|
if (amount == 0) {
|
2019-08-17 13:28:06 +00:00
|
|
|
return expr.left
|
|
|
|
}
|
2020-10-30 15:26:19 +00:00
|
|
|
val targetIDt = expr.left.inferType(program)
|
|
|
|
if(!targetIDt.isKnown)
|
|
|
|
throw FatalAstException("unknown dt")
|
2021-10-12 22:21:38 +00:00
|
|
|
when (val targetDt = targetIDt.getOr(DataType.UNDEFINED)) {
|
2019-08-17 13:28:06 +00:00
|
|
|
DataType.UBYTE, DataType.BYTE -> {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (amount >= 8) {
|
2022-10-29 13:23:39 +00:00
|
|
|
errors.warn("shift always results in 0", expr.position)
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral(targetDt, 0.0, expr.position)
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-15 02:00:41 +00:00
|
|
|
DataType.UWORD -> {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (amount >= 16) {
|
2022-10-29 13:23:39 +00:00
|
|
|
errors.warn("shift always results in 0", expr.position)
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral(targetDt, 0.0, expr.position)
|
2022-08-11 20:25:15 +00:00
|
|
|
}
|
|
|
|
else if(amount==8) {
|
|
|
|
// shift left by 8 bits is just a byte operation: mkword(lsb(X), 0)
|
|
|
|
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position)
|
|
|
|
return FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(lsb, NumericLiteral(DataType.UBYTE, 0.0, expr.position)), expr.position)
|
|
|
|
}
|
|
|
|
else if (amount > 8) {
|
|
|
|
// same as above but with residual shifts.
|
2022-01-07 20:02:37 +00:00
|
|
|
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position)
|
2022-02-10 23:21:40 +00:00
|
|
|
val shifted = BinaryExpression(lsb, "<<", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position)
|
|
|
|
return FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(shifted, NumericLiteral.optimalInteger(0, expr.position)), expr.position)
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-15 02:00:41 +00:00
|
|
|
DataType.WORD -> {
|
|
|
|
if (amount >= 16) {
|
|
|
|
errors.warn("shift always results in 0", expr.position)
|
|
|
|
return NumericLiteral(targetDt, 0.0, expr.position)
|
|
|
|
}
|
|
|
|
else if(amount==8) {
|
|
|
|
// shift left by 8 bits is just a byte operation: mkword(lsb(X), 0)
|
|
|
|
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position)
|
|
|
|
val mkword = FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(lsb, NumericLiteral(DataType.UBYTE, 0.0, expr.position)), expr.position)
|
|
|
|
return TypecastExpression(mkword, DataType.WORD, true, expr.position)
|
|
|
|
}
|
|
|
|
else if (amount > 8) {
|
|
|
|
// same as above but with residual shifts.
|
|
|
|
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position)
|
|
|
|
val shifted = BinaryExpression(lsb, "<<", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position)
|
|
|
|
val mkword = FunctionCallExpression(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(shifted, NumericLiteral.optimalInteger(0, expr.position)), expr.position)
|
|
|
|
return TypecastExpression(mkword, DataType.WORD, true, expr.position)
|
|
|
|
}
|
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
else -> {
|
|
|
|
}
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun optimizeShiftRight(expr: BinaryExpression, amountLv: NumericLiteral?): Expression? {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (amountLv == null)
|
|
|
|
return null
|
2019-08-17 13:28:06 +00:00
|
|
|
|
2020-03-21 22:09:18 +00:00
|
|
|
val amount = amountLv.number.toInt()
|
|
|
|
if (amount == 0) {
|
2019-08-17 13:28:06 +00:00
|
|
|
return expr.left
|
|
|
|
}
|
2020-10-30 15:26:19 +00:00
|
|
|
val idt = expr.left.inferType(program)
|
|
|
|
if(!idt.isKnown)
|
|
|
|
throw FatalAstException("unknown dt")
|
2021-10-12 22:21:38 +00:00
|
|
|
when (idt.getOr(DataType.UNDEFINED)) {
|
2019-08-17 13:28:06 +00:00
|
|
|
DataType.UBYTE -> {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (amount >= 8) {
|
2022-10-29 13:23:39 +00:00
|
|
|
errors.warn("shift always results in 0", expr.position)
|
2022-02-10 23:21:40 +00:00
|
|
|
return NumericLiteral.optimalInteger(0, expr.position)
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.BYTE -> {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (amount > 8) {
|
2022-02-10 23:21:40 +00:00
|
|
|
expr.right = NumericLiteral.optimalInteger(8, expr.right.position)
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.UWORD -> {
|
2020-03-21 22:09:18 +00:00
|
|
|
if (amount >= 16) {
|
2024-01-06 23:01:00 +00:00
|
|
|
errors.err("useless to shift by more than 15 bits", expr.position)
|
|
|
|
return null
|
2021-01-07 21:49:54 +00:00
|
|
|
}
|
2022-08-11 20:25:15 +00:00
|
|
|
else if(amount==8) {
|
|
|
|
// shift right by 8 bits is just a byte operation: msb(X) as uword
|
|
|
|
val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position)
|
|
|
|
return TypecastExpression(msb, DataType.UWORD, true, expr.position)
|
|
|
|
}
|
2022-01-28 12:54:06 +00:00
|
|
|
else if (amount > 8) {
|
2022-08-11 20:25:15 +00:00
|
|
|
// same as above but with residual shifts.
|
2022-01-07 20:02:37 +00:00
|
|
|
val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position)
|
2022-02-10 23:21:40 +00:00
|
|
|
return TypecastExpression(BinaryExpression(msb, ">>", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position), DataType.UWORD, true, expr.position)
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.WORD -> {
|
2024-01-06 23:01:00 +00:00
|
|
|
if (amount >= 16) {
|
|
|
|
errors.err("useless to shift by more than 15 bits", expr.position)
|
2020-03-21 22:09:18 +00:00
|
|
|
return null
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
2024-01-06 23:01:00 +00:00
|
|
|
else if(amount == 8) {
|
2024-01-16 00:08:16 +00:00
|
|
|
// shift right by 8 bits is just a byte operation: msb(X) as byte (will get converted to word later)
|
2024-01-06 23:01:00 +00:00
|
|
|
val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position)
|
|
|
|
return TypecastExpression(msb, DataType.BYTE, true, expr.position)
|
|
|
|
}
|
|
|
|
else if(amount > 8) {
|
2024-01-16 00:08:16 +00:00
|
|
|
// same as above but with residual shifts. Take care to do signed shift.
|
2024-01-06 23:01:00 +00:00
|
|
|
val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position)
|
2024-01-16 00:08:16 +00:00
|
|
|
val signed = TypecastExpression(msb, DataType.BYTE, true, expr.position)
|
|
|
|
return BinaryExpression(signed, ">>", NumericLiteral.optimalInteger(amount - 8, expr.position), expr.position)
|
2024-01-06 23:01:00 +00:00
|
|
|
}
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
else -> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private fun reorderAssociativeWithConstant(expr: BinaryExpression, leftVal: NumericLiteral?): BinExprWithConstants {
|
2022-06-12 20:55:23 +00:00
|
|
|
if (expr.operator in AssociativeOperators && leftVal != null && maySwapOperandOrder(expr)) {
|
2020-03-21 22:09:18 +00:00
|
|
|
// swap left and right so that right is always the constant
|
|
|
|
val tmp = expr.left
|
|
|
|
expr.left = expr.right
|
|
|
|
expr.right = tmp
|
2020-12-14 20:37:40 +00:00
|
|
|
return BinExprWithConstants(expr, expr.right.constValue(program), leftVal)
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
2020-12-14 20:37:40 +00:00
|
|
|
return BinExprWithConstants(expr, leftVal, expr.right.constValue(program))
|
2019-08-17 13:28:06 +00:00
|
|
|
}
|
2020-03-21 22:09:18 +00:00
|
|
|
|
2022-02-10 23:21:40 +00:00
|
|
|
private data class BinExprWithConstants(val expr: BinaryExpression, val leftVal: NumericLiteral?, val rightVal: NumericLiteral?)
|
2020-03-21 22:09:18 +00:00
|
|
|
|
2021-12-27 19:46:10 +00:00
|
|
|
}
|