diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index 2b38d5df5..cdbcbc0c6 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -440,6 +440,52 @@ jump p8_label_gen_2 } else -> {} } + + fun optimizeImmediateLoadAssociative(replacementOpcode: Opcode) { + + fun getImmediateLoad(reg: Int): Pair? { + // look if the given register gets an immediate value 1 or 2 istructions back + // returns (index of load instruction, immediate value) or null. + if(idx>=1) { + val previous = indexedInstructions[idx-1].value + if(previous.opcode==Opcode.LOAD && previous.reg1==reg) + return idx-1 to previous.immediate!! + } + if(idx>=2) { + val previous = indexedInstructions[idx-2].value + if(previous.opcode==Opcode.LOAD && previous.reg1==reg) + return idx-2 to previous.immediate!! + } + return null + } + + val immediate1 = getImmediateLoad(ins.reg1!!) + if(immediate1!=null) { + chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg2, immediate = immediate1.second) + chunk.instructions.removeAt(immediate1.first) + changed=true + } else { + val immediate2 = getImmediateLoad(ins.reg2!!) + if (immediate2 != null) { + chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg1, immediate = immediate2.second) + chunk.instructions.removeAt(immediate2.first) + changed=true + } + } + } + + // try to use immediate arithmetic instruction if possible + when(ins.opcode) { + Opcode.ADDR -> optimizeImmediateLoadAssociative(Opcode.ADD) + Opcode.MULR -> optimizeImmediateLoadAssociative(Opcode.MUL) + Opcode.MULSR -> optimizeImmediateLoadAssociative(Opcode.MULS) +// Opcode.SUBR -> TODO("ir peephole Subr") +// Opcode.DIVR -> TODO("ir peephole Divr") +// Opcode.DIVSR -> TODO("ir peephole Divsr") +// Opcode.MODR -> TODO("ir peephole Modr") +// Opcode.DIVMODR -> TODO("ir peephole DivModr") + else -> {} + } } return changed } diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index a498ede33..194672b00 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -480,18 +480,31 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, override fun after(addressOf: AddressOf, parent: Node): Iterable { if(addressOf.arrayIndex!=null) { - val tgt = addressOf.identifier?.constValue(program) - if (tgt != null && tgt.type.isInteger) { - // &constant[idx] --> constant + idx - val indexExpr = addressOf.arrayIndex!!.indexExpr - val right = if(indexExpr.inferType(program) issimpletype tgt.type) - indexExpr - else - TypecastExpression(indexExpr, DataType.forDt(tgt.type), true, indexExpr.position) - val add = BinaryExpression(tgt, "+", right, addressOf.position) - return listOf( - IAstModification.ReplaceNode(addressOf, add, parent) - ) + val tgt = addressOf.identifier + if(tgt!=null) { + val constAddress = tgt.constValue(program) + if (constAddress != null && constAddress.type.isInteger) { + // &constant[idx] --> constant + idx + val indexExpr = addressOf.arrayIndex!!.indexExpr + val right = if (indexExpr.inferType(program) issimpletype constAddress.type) + indexExpr + else + TypecastExpression(indexExpr, DataType.forDt(constAddress.type), true, indexExpr.position) + val add = BinaryExpression(constAddress, "+", right, addressOf.position) + return listOf(IAstModification.ReplaceNode(addressOf, add, parent)) + } else { + val decl = tgt.targetVarDecl()!! + if(decl.datatype.isInteger) { + // &addressvar[idx] --> addressvar + idx + val indexExpr = addressOf.arrayIndex!!.indexExpr + val right = if (indexExpr.inferType(program) istype decl.datatype) + indexExpr + else + TypecastExpression(indexExpr, decl.datatype, true, indexExpr.position) + val add = BinaryExpression(tgt, "+", right, addressOf.position) + return listOf(IAstModification.ReplaceNode(addressOf, add, parent)) + } + } } } return noModifications diff --git a/docs/source/todo.rst b/docs/source/todo.rst index fd43ac9bc..baea4a692 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -88,7 +88,7 @@ IR/VM - implement fast code paths for TODO("inplace split.... - implement more TODOs in AssignmentGen - do something with the 'split' tag on split word arrays -- add more optimizations in IRPeepholeOptimizer +- add more optimizations in IRPeepholeOptimizer, implement the TODOs in there at least - idea: replace all scalar variables that are not @shared by an allocated register. Keep a table of the variable to register mapping (including the datatype) global initialization values are simply a list of LOAD instructions. Variables replaced include all subroutine parameters? Or not? So the only variables that remain as variables are arrays and strings.