diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 3f01d8978..d350feb5d 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -360,6 +360,12 @@ internal class AssignmentAsmGen(private val program: Program, if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) { if(expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes && expr.left.isSimple && expr.right.isSimple) { +// if(expr.right is NumericLiteral || expr.right is IdentifierReference) { +// TODO("optimized code for logical with right number/variable arg (byte)") +// } else if(expr.left is NumericLiteral || expr.left is IdentifierReference) { +// TODO("optimized code for logical with left number/variable arg (byte)") +// } + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.saveRegisterStack(CpuRegister.A, false) assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine) @@ -375,6 +381,11 @@ internal class AssignmentAsmGen(private val program: Program, } if(expr.left.inferType(program).isWords && expr.right.inferType(program).isWords && expr.left.isSimple && expr.right.isSimple) { +// if(expr.right is NumericLiteral || expr.right is IdentifierReference) { +// TODO("optimized code for logical with right number/variable arg (word)") +// } else if(expr.left is NumericLiteral || expr.left is IdentifierReference) { +// TODO("optimized code for logical with left number/variable arg (word)") +// } assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index 6dcbded5d..c59141e3f 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -10,13 +10,14 @@ import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.* +import prog8.code.target.VMTarget import kotlin.math.abs import kotlin.math.log2 import kotlin.math.pow // TODO add more peephole expression optimizations? Investigate what optimizations binaryen has, also see https://egorbo.com/peephole-optimizations.html -class ExpressionSimplifier(private val program: Program) : AstWalker() { +class ExpressionSimplifier(private val program: Program, private val compTarget: ICompilationTarget) : AstWalker() { private val powersOfTwo = (1..16).map { (2.0).pow(it) }.toSet() private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet() @@ -71,6 +72,22 @@ class ExpressionSimplifier(private val program: Program) : AstWalker() { } } } + + if(compTarget.name!=VMTarget.NAME) { + val booleanCondition = ifElse.condition as? BinaryExpression + if(booleanCondition!=null && booleanCondition.operator=="&") { + // special optimization of WORD & $ff00 -> just and the msb of WORD with $ff + val rightNum = booleanCondition.right as? NumericLiteral + if(rightNum!=null && rightNum.type==DataType.UWORD && (rightNum.number.toInt() and 0x00ff)==0) { + 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)) + } + } + } + return noModifications } diff --git a/codeOptimizers/src/prog8/optimizer/Extensions.kt b/codeOptimizers/src/prog8/optimizer/Extensions.kt index 3b7716721..78b9478fe 100644 --- a/codeOptimizers/src/prog8/optimizer/Extensions.kt +++ b/codeOptimizers/src/prog8/optimizer/Extensions.kt @@ -60,8 +60,8 @@ fun Program.inlineSubroutines(): Int { return inliner.applyModifications() } -fun Program.simplifyExpressions() : Int { - val opti = ExpressionSimplifier(this) +fun Program.simplifyExpressions(target: ICompilationTarget) : Int { + val opti = ExpressionSimplifier(this, target) opti.visit(this) return opti.applyModifications() } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 2560595f8..e901e9af8 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -358,7 +358,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e remover.applyModifications() while (true) { // keep optimizing expressions and statements until no more steps remain - val optsDone1 = program.simplifyExpressions() + val optsDone1 = program.simplifyExpressions(compTarget) val optsDone2 = program.splitBinaryExpressions(compilerOptions) val optsDone3 = program.optimizeStatements(errors, functions, compTarget) val optsDone4 = program.inlineSubroutines() diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4a605dac6..132f6eca0 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,9 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- finish the logical expression optimizations set in TODO's in attemptAssignOptimizedBinexpr() +- try more benchmarks from https://gglabs.us/node/2293 + ... @@ -77,6 +80,7 @@ Optimizations: - VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served? - when a loopvariable of a forloop isn't referenced in the body, and the iterations are known, replace the loop by a repeatloop but we have no efficient way right now to see if the body references a variable. +- optimize function argument expressions better (use temporary variables to replace non-simple expressions?) STRUCTS again? diff --git a/examples/test.p8 b/examples/test.p8 index 60dc270d6..6b9758883 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,16 +3,17 @@ main { sub start() { - ubyte[] buffer = [$11,$22,$33,$44] - uword data = &buffer - uword crc = $ffff - crc ^= mkword(@(data), 0) - txt.print_uwhex(crc, true) - crc = $ffff - ubyte variable = @(data) - crc ^= mkword(variable, 0) - txt.print_uwhex(crc, true) + txt.print_uwhex(crc | (crc & $8000), true) +; if crc & $8000 ; msb(crc) & $80 +; txt.print("yes") +; else +; txt.print("fail!") +; +; if msb(crc) & $80 +; txt.print("yes") +; else +; txt.print("fail!") } ; sub start2() {