diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index c98ba260f..572434877 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -212,21 +212,27 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() { } } } - else if(expr.operator=="*" && leftBinExpr.operator=="*") { + else if(expr.operator=="*") { val c2 = leftBinExpr.right.constValue(program) if(c2!=null) { - // (X * C1) * C2 --> X * (C1*C2) - // TODO (X * C1) / C2 --> X * (C1/C2) - val constants = BinaryExpression(c2, "*", rightconst, c2.position) - val newExpr = BinaryExpression(leftBinExpr.left, "*", constants, expr.position) - return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) + if(leftBinExpr.operator=="*") { + // (X * C2) * rightConst --> X * (rightConst*C2) + val constants = BinaryExpression(rightconst, "*", c2, c2.position) + val newExpr = BinaryExpression(leftBinExpr.left, "*", constants, expr.position) + return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) + } else if (leftBinExpr.operator=="/") { + // (X / C2) * rightConst --> X * (rightConst/C2) + val constants = BinaryExpression(rightconst, "/", c2, c2.position) + val newExpr = BinaryExpression(leftBinExpr.left, "*", constants, expr.position) + return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) + } } } - else if(expr.operator=="/" && leftBinExpr.operator=="/") { + else if(expr.operator=="/") { val c2 = leftBinExpr.right.constValue(program) - if(c2!=null) { + if(c2!=null && leftBinExpr.operator=="/") { // (X / C1) / C2 --> X / (C1*C2) - // TODO (X / C1) * C2 --> X * (C2/C1) + // NOTE: do not optimize (X * C1) / C2 --> X * (C1/C2) because this causes precision loss on integers val constants = BinaryExpression(c2, "*", rightconst, c2.position) val newExpr = BinaryExpression(leftBinExpr.left, "/", constants, expr.position) return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index c35ee174d..e070f24da 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -167,11 +167,12 @@ class TestOptimization: FunSpec({ val source = """ main { sub start() { - ; TODO other variants of this const folding word llw = 300 cx16.r0s = 9 * 2 * 10 * llw cx16.r1s = llw * 9 * 2 * 10 - cx16.r2s = llw / 20 / 3 + cx16.r2s = llw / 30 / 3 + cx16.r3s = llw / 2 * 10 + cx16.r4s = llw * 90 / 5 ; not optimized because of loss of integer division precision } }""" val result = compileText(C64Target, true, source, writeAssembly = false).assertSuccess() @@ -184,9 +185,14 @@ class TestOptimization: FunSpec({ // cx16.r1s = llw // cx16.r1s *= 180 // cx16.r2s = llw -// cx16.r2s /= 100 +// cx16.r2s /= 90 +// cx16.r3s = llw +// cx16.r3s *= 5 +// cx16.r4s = llw +// cx16.r4s *= 90 +// cx16.r4s /= 5 val stmts = result.program.entrypoint.statements - stmts.size shouldBe 8 + stmts.size shouldBe 13 val mulR0Value = (stmts[3] as Assignment).value val binexpr0 = mulR0Value as BinaryExpression @@ -199,7 +205,19 @@ class TestOptimization: FunSpec({ val divR2Value = (stmts[7] as Assignment).value val binexpr2 = divR2Value as BinaryExpression binexpr2.operator shouldBe "/" - binexpr2.right shouldBe NumericLiteralValue(DataType.UWORD, 60.0, Position.DUMMY) + binexpr2.right shouldBe NumericLiteralValue(DataType.UWORD, 90.0, Position.DUMMY) + val mulR3Value = (stmts[9] as Assignment).value + val binexpr3 = mulR3Value as BinaryExpression + binexpr3.operator shouldBe "*" + binexpr3.right shouldBe NumericLiteralValue(DataType.UWORD, 5.0, Position.DUMMY) + val mulR4Value = (stmts[11] as Assignment).value + val binexpr4 = mulR4Value as BinaryExpression + binexpr4.operator shouldBe "*" + binexpr4.right shouldBe NumericLiteralValue(DataType.UWORD, 90.0, Position.DUMMY) + val divR4Value = (stmts[12] as Assignment).value + val binexpr4b = divR4Value as BinaryExpression + binexpr4b.operator shouldBe "/" + binexpr4b.right shouldBe NumericLiteralValue(DataType.UWORD, 5.0, Position.DUMMY) } test("constantfolded and silently typecasted for initializervalues") { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 2b70e34e5..8f90aede8 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next compiler release (7.5) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -more const-foldings check correctness of inplaceModification_byte_value_to_pointer() ... diff --git a/examples/test.p8 b/examples/test.p8 index 31f060482..a47227daf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,12 +3,11 @@ main { sub start() { - ; TODO other variants of this const folding word llw = 300 cx16.r0s = 9 * 2 * 10 * llw cx16.r1s = llw * 9 * 2 * 10 - cx16.r2s = llw * 9 / 4 - cx16.r3s = llw / 20 / 5 - cx16.r4s = llw / 20 * 5 + cx16.r3s = llw / 30 / 3 + cx16.r4s = llw / 2 * 10 + cx16.r5s = llw * 90 / 5 ; not optimized because of loss of integer division precision } }