From b0704e86f05792efc0a02a5e7885849b0a818d94 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 25 Aug 2022 21:02:18 +0200 Subject: [PATCH] block structure --- .../codegen/experimental/AssignmentGen.kt | 20 +-- .../codegen/experimental/BuiltinFuncGen.kt | 61 ++++---- .../src/prog8/codegen/experimental/CodeGen.kt | 144 +++++++++--------- .../codegen/experimental/ExpressionGen.kt | 78 +++++----- .../experimental/IRPeepholeOptimizer.kt | 98 ++++++------ .../prog8/codegen/experimental/IRProgram.kt | 99 ++++++++---- compiler/src/prog8/compiler/Compiler.kt | 6 +- 7 files changed, 281 insertions(+), 225 deletions(-) diff --git a/codeGenExperimental/src/prog8/codegen/experimental/AssignmentGen.kt b/codeGenExperimental/src/prog8/codegen/experimental/AssignmentGen.kt index df61c7ed6..b61db2972 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/AssignmentGen.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/AssignmentGen.kt @@ -46,11 +46,11 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio origAssign: PtAssignment ): VmCodeChunk { val vmDt = codeGen.vmType(value.type) - val code = VmCodeChunk() + val code = VmCodeChunk(origAssign.position) when(value) { is PtIdentifier -> return code // do nothing, x=x null assignment. is PtMachineRegister -> return code // do nothing, reg=reg null assignment - is PtPrefix -> return inplacePrefix(value.operator, vmDt, address) + is PtPrefix -> return inplacePrefix(value.operator, vmDt, address, value.position) is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, origAssign) is PtMemoryByte -> { return if (!codeGen.options.compTarget.machine.isIOAddress(address.toUInt())) @@ -97,8 +97,8 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio return fallbackAssign(origAssign) } - private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int): VmCodeChunk { - val code= VmCodeChunk() + private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int, position: Position): VmCodeChunk { + val code= VmCodeChunk(position) when(operator) { "+" -> { } "-" -> { @@ -122,7 +122,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio val array = assignment.target.array val vmDt = codeGen.vmType(assignment.value.type) - val code = VmCodeChunk() + val code = VmCodeChunk(assignment.position) var resultRegister = -1 var resultFpRegister = -1 val zero = codeGen.isZero(assignment.value) @@ -181,7 +181,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=variableAddr) } else { val indexReg = codeGen.vmRegisters.nextFree() - code += loadIndexReg(array, itemsize, indexReg) + code += loadIndexReg(array, itemsize, indexReg, array.position) code += VmCodeInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, value=variableAddr) } } else { @@ -191,7 +191,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio code += VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value=variableAddr) } else { val indexReg = codeGen.vmRegisters.nextFree() - code += loadIndexReg(array, itemsize, indexReg) + code += loadIndexReg(array, itemsize, indexReg, array.position) code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr) } } else { @@ -200,7 +200,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value=variableAddr) } else { val indexReg = codeGen.vmRegisters.nextFree() - code += loadIndexReg(array, itemsize, indexReg) + code += loadIndexReg(array, itemsize, indexReg, array.position) code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr) } } @@ -231,8 +231,8 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio return code } - private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int): VmCodeChunk { - val code = VmCodeChunk() + private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(itemsize==1) { code += expressionEval.translateExpression(array.index, indexReg, -1) } diff --git a/codeGenExperimental/src/prog8/codegen/experimental/BuiltinFuncGen.kt b/codeGenExperimental/src/prog8/codegen/experimental/BuiltinFuncGen.kt index a1483a335..8707420aa 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/BuiltinFuncGen.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/BuiltinFuncGen.kt @@ -4,6 +4,7 @@ import prog8.code.StStaticVariable import prog8.code.ast.* import prog8.code.core.AssemblyError import prog8.code.core.DataType +import prog8.code.core.Position import prog8.vm.Opcode import prog8.vm.Syscall import prog8.vm.VmDataType @@ -25,9 +26,9 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: "rsave", "rsavex", "rrestore", - "rrestorex" -> VmCodeChunk() // vm doesn't have registers to save/restore - "rnd" -> funcRnd(resultRegister) - "rndw" -> funcRndw(resultRegister) + "rrestorex" -> VmCodeChunk(call.position) // vm doesn't have registers to save/restore + "rnd" -> funcRnd(resultRegister, call.position) + "rndw" -> funcRndw(resultRegister, call.position) "callfar" -> throw AssemblyError("callfar() is for cx16 target only") "callrom" -> throw AssemblyError("callrom() is for cx16 target only") "msb" -> funcMsb(call, resultRegister) @@ -37,7 +38,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: "peekw" -> funcPeekW(call, resultRegister) "poke" -> funcPoke(call) "pokew" -> funcPokeW(call) - "pokemon" -> VmCodeChunk() + "pokemon" -> VmCodeChunk(call.position) "mkword" -> funcMkword(call, resultRegister) "sort" -> funcSort(call) "reverse" -> funcReverse(call) @@ -50,7 +51,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcCmp(call: PtBuiltinFunctionCall): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val leftRegister = codeGen.vmRegisters.nextFree() val rightRegister = codeGen.vmRegisters.nextFree() code += exprGen.translateExpression(call.args[0], leftRegister, -1) @@ -62,7 +63,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val syscall = when (array.dt) { DataType.ARRAY_UB, @@ -92,7 +93,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: DataType.ARRAY_F -> Syscall.ALL_FLOAT else -> throw IllegalArgumentException("weird type") } - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += exprGen.translateExpression(call.args[0], 0, -1) code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length) code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal) @@ -102,7 +103,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val sourceDt = call.args.single().type if(sourceDt!=DataType.UWORD) { code += exprGen.translateExpression(call.args[0], resultRegister, -1) @@ -136,7 +137,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val reg = codeGen.vmRegisters.nextFree() code += exprGen.translateExpression(call.args.single(), reg, -1) code += VmCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg) @@ -144,7 +145,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val reg = codeGen.vmRegisters.nextFree() code += exprGen.translateExpression(call.args.single(), reg, -1) code += VmCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg) @@ -152,7 +153,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPop(call: PtBuiltinFunctionCall): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val reg = codeGen.vmRegisters.nextFree() code += VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg) code += assignRegisterTo(call.args.single(), reg) @@ -160,7 +161,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPopw(call: PtBuiltinFunctionCall): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val reg = codeGen.vmRegisters.nextFree() code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=reg) code += assignRegisterTo(call.args.single(), reg) @@ -168,7 +169,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPush(call: PtBuiltinFunctionCall): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val reg = codeGen.vmRegisters.nextFree() code += exprGen.translateExpression(call.args.single(), reg, -1) code += VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg) @@ -176,7 +177,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPushw(call: PtBuiltinFunctionCall): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) val reg = codeGen.vmRegisters.nextFree() code += exprGen.translateExpression(call.args.single(), reg, -1) code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg) @@ -193,7 +194,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: DataType.ARRAY_F -> Syscall.REVERSE_FLOATS else -> throw IllegalArgumentException("weird type to reverse") } - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += exprGen.translateExpression(call.args[0], 0, -1) code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length) code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal) @@ -213,7 +214,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported") else -> throw IllegalArgumentException("weird type to sort") } - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += exprGen.translateExpression(call.args[0], 0, -1) code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length) code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal) @@ -222,7 +223,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { val msbReg = codeGen.vmRegisters.nextFree() - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += exprGen.translateExpression(call.args[0], msbReg, -1) code += exprGen.translateExpression(call.args[1], resultRegister, -1) code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg) @@ -230,7 +231,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) if(codeGen.isZero(call.args[1])) { if (call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() @@ -257,7 +258,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) if(codeGen.isZero(call.args[1])) { if (call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() @@ -284,7 +285,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) if(call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() code += VmCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address) @@ -297,7 +298,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) if(call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address) @@ -309,14 +310,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: return code } - private fun funcRnd(resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + private fun funcRnd(resultRegister: Int, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) code += VmCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister) return code } - private fun funcRndw(resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + private fun funcRndw(resultRegister: Int, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) code += VmCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister) return code } @@ -326,20 +327,20 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: val size = (call.args[1] as PtNumber).number.toUInt() val align = (call.args[2] as PtNumber).number.toUInt() val label = codeGen.addMemorySlab(name, size, align, call.position) - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = listOf(label)) return code } private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += exprGen.translateExpression(call.args.single(), resultRegister, -1) // note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here. return code } private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += exprGen.translateExpression(call.args.single(), resultRegister, -1) code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister) // note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here. @@ -348,7 +349,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { val vmDt = codeGen.vmType(call.args[0].type) - val code = VmCodeChunk() + val code = VmCodeChunk(call.position) code += exprGen.translateExpression(call.args[0], resultRegister, -1) code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister) code += assignRegisterTo(call.args[0], resultRegister) @@ -356,7 +357,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } private fun assignRegisterTo(target: PtExpression, register: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(target.position) val assignment = PtAssignment(target.position) val assignTarget = PtAssignTarget(target.position) assignTarget.children.add(target) diff --git a/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt b/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt index 3efd8213b..6d63f58a8 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt @@ -53,7 +53,7 @@ class CodeGen(internal val program: PtProgram, if(!options.dontReinitGlobals) { // collect global variables initializers program.allBlocks().forEach { - val code = VmCodeChunk() + val code = VmCodeChunk(it.position) it.children.filterIsInstance().forEach { assign -> code += assignmentGen.translate(assign) } irProg.addGlobalInits(code) } @@ -82,18 +82,17 @@ class CodeGen(internal val program: PtProgram, internal fun translateNode(node: PtNode): VmCodeChunk { val code = when(node) { - is PtBlock -> translate(node) is PtSub -> translate(node) is PtAsmSub -> translate(node) - is PtScopeVarsDecls -> VmCodeChunk() // vars should be looked up via symbol table - is PtVariable -> VmCodeChunk() // var should be looked up via symbol table - is PtMemMapped -> VmCodeChunk() // memmapped var should be looked up via symbol table - is PtConstant -> VmCodeChunk() // constants have all been folded into the code + is PtScopeVarsDecls -> VmCodeChunk(node.position) // vars should be looked up via symbol table + is PtVariable -> VmCodeChunk(node.position) // var should be looked up via symbol table + is PtMemMapped -> VmCodeChunk(node.position) // memmapped var should be looked up via symbol table + is PtConstant -> VmCodeChunk(node.position) // constants have all been folded into the code is PtAssignment -> assignmentGen.translate(node) - is PtNodeGroup -> translateGroup(node.children) + is PtNodeGroup -> translateGroup(node.children, node.position) is PtBuiltinFunctionCall -> translateBuiltinFunc(node, 0) is PtFunctionCall -> expressionEval.translate(node, 0, 0) - is PtNop -> VmCodeChunk() + is PtNop -> VmCodeChunk(node.position) is PtReturn -> translate(node) is PtJump -> translate(node) is PtWhen -> translate(node) @@ -101,11 +100,11 @@ class CodeGen(internal val program: PtProgram, is PtIfElse -> translate(node) is PtPostIncrDecr -> translate(node) is PtRepeatLoop -> translate(node) - is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName)) - is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT)) + is PtLabel -> VmCodeChunk(node.position, VmCodeLabel(node.scopedName)) + is PtBreakpoint -> VmCodeChunk(node.position, VmCodeInstruction(Opcode.BREAKPOINT)) is PtConditionalBranch -> translate(node) - is PtInlineAssembly -> VmCodeChunk(VmCodeInlineAsm(node.assembly)) - is PtIncludeBinary -> VmCodeChunk(VmCodeInlineBinary(node.file, node.offset, node.length)) + is PtInlineAssembly -> VmInlineAsmChunk(node.assembly, node.position) + is PtIncludeBinary -> VmCodeChunk(node.position, VmCodeInlineBinary(node.file, node.offset, node.length)) is PtAddressOf, is PtContainmentCheck, is PtMemoryByte, @@ -121,16 +120,15 @@ class CodeGen(internal val program: PtProgram, is PtSubroutineParameter, is PtNumber, is PtArray, + is PtBlock, is PtString -> throw AssemblyError("should not occur as separate statement node ${node.position}") else -> TODO("missing codegen for $node") } - if(code.lines.isNotEmpty() && node.position.line!=0) - code.lines.add(0, VmCodeComment(node.position.toString())) return code } private fun translate(branch: PtConditionalBranch): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(branch.position) val elseLabel = createLabelName() // note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part code += when(branch.condition) { @@ -157,9 +155,9 @@ class CodeGen(internal val program: PtProgram, } private fun translate(whenStmt: PtWhen): VmCodeChunk { + val code = VmCodeChunk(whenStmt.position) if(whenStmt.choices.children.isEmpty()) - return VmCodeChunk() - val code = VmCodeChunk() + return code val valueReg = vmRegisters.nextFree() val choiceReg = vmRegisters.nextFree() val valueDt = vmType(whenStmt.value.type) @@ -200,7 +198,7 @@ class CodeGen(internal val program: PtProgram, private fun translate(forLoop: PtForLoop): VmCodeChunk { val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable val iterable = forLoop.iterable - val code = VmCodeChunk() + val code = VmCodeChunk(forLoop.position) when(iterable) { is PtRange -> { if(iterable.from is PtNumber && iterable.to is PtNumber) @@ -240,7 +238,7 @@ class CodeGen(internal val program: PtProgram, code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress) code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress) code += translateNode(forLoop.statements) - code += addConstReg(VmDataType.BYTE, indexReg, elementSize) + code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position) code += VmCodeInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel) } else if(lengthBytes==256) { code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0) @@ -248,7 +246,7 @@ class CodeGen(internal val program: PtProgram, code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress) code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress) code += translateNode(forLoop.statements) - code += addConstReg(VmDataType.BYTE, indexReg, elementSize) + code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position) code += VmCodeInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel) } else { throw AssemblyError("iterator length should never exceed 256") @@ -270,14 +268,14 @@ class CodeGen(internal val program: PtProgram, val loopvarAddress = allocations.get(loopvar.scopedName) val loopvarDt = vmType(loopvar.dt) val loopLabel = createLabelName() - val code = VmCodeChunk() + val code = VmCodeChunk(forLoop.position) code += expressionEval.translateExpression(iterable.to, endvalueReg, -1) code += expressionEval.translateExpression(iterable.from, indexReg, -1) code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress) code += VmCodeLabel(loopLabel) code += translateNode(forLoop.statements) - code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step) + code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step, iterable.position) code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress) val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel) @@ -298,7 +296,7 @@ class CodeGen(internal val program: PtProgram, if(step>0 && rangeEndUntypedrangeStart) throw AssemblyError("empty range") val rangeEndWrapped = if(loopvarDt==VmDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535 - val code = VmCodeChunk() + val code = VmCodeChunk(forLoop.position) val endvalueReg: Int if(rangeEndWrapped!=0) { endvalueReg = vmRegisters.nextFree() @@ -310,7 +308,7 @@ class CodeGen(internal val program: PtProgram, code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress) code += VmCodeLabel(loopLabel) code += translateNode(forLoop.statements) - code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step) + code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step, iterable.position) code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress) code += if(rangeEndWrapped==0) { VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel) @@ -320,8 +318,8 @@ class CodeGen(internal val program: PtProgram, return code } - private fun addConstReg(dt: VmDataType, reg: Int, value: Int): VmCodeChunk { - val code = VmCodeChunk() + private fun addConstReg(dt: VmDataType, reg: Int, value: Int, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) when(value) { 0 -> { /* do nothing */ } 1 -> { @@ -349,8 +347,8 @@ class CodeGen(internal val program: PtProgram, return code } - private fun addConstMem(dt: VmDataType, address: UInt, value: Int): VmCodeChunk { - val code = VmCodeChunk() + private fun addConstMem(dt: VmDataType, address: UInt, value: Int, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) when(value) { 0 -> { /* do nothing */ } 1 -> { @@ -382,8 +380,8 @@ class CodeGen(internal val program: PtProgram, return code } - internal fun multiplyByConstFloat(fpReg: Int, factor: Float): VmCodeChunk { - val code = VmCodeChunk() + internal fun multiplyByConstFloat(fpReg: Int, factor: Float, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1f) return code code += if(factor==0f) { @@ -394,8 +392,8 @@ class CodeGen(internal val program: PtProgram, return code } - internal fun multiplyByConstFloatInplace(address: Int, factor: Float): VmCodeChunk { - val code = VmCodeChunk() + internal fun multiplyByConstFloatInplace(address: Int, factor: Float, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1f) return code if(factor==0f) { @@ -410,8 +408,8 @@ class CodeGen(internal val program: PtProgram, internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() } - internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk { - val code = VmCodeChunk() + internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -434,8 +432,8 @@ class CodeGen(internal val program: PtProgram, return code } - internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int): VmCodeChunk { - val code = VmCodeChunk() + internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -461,8 +459,8 @@ class CodeGen(internal val program: PtProgram, return code } - internal fun divideByConstFloat(fpReg: Int, factor: Float): VmCodeChunk { - val code = VmCodeChunk() + internal fun divideByConstFloat(fpReg: Int, factor: Float, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1f) return code code += if(factor==0f) { @@ -473,8 +471,8 @@ class CodeGen(internal val program: PtProgram, return code } - internal fun divideByConstFloatInplace(address: Int, factor: Float): VmCodeChunk { - val code = VmCodeChunk() + internal fun divideByConstFloatInplace(address: Int, factor: Float, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1f) return code if(factor==0f) { @@ -489,8 +487,8 @@ class CodeGen(internal val program: PtProgram, return code } - internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean): VmCodeChunk { - val code = VmCodeChunk() + internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -518,8 +516,8 @@ class CodeGen(internal val program: PtProgram, return code } - internal fun divideByConstInplace(dt: VmDataType, address: Int, factor: Int, signed: Boolean): VmCodeChunk { - val code = VmCodeChunk() + internal fun divideByConstInplace(dt: VmDataType, address: Int, factor: Int, signed: Boolean, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -558,7 +556,7 @@ class CodeGen(internal val program: PtProgram, val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) val vmDt = vmType(ifElse.condition.left.type) - val code = VmCodeChunk() + val code = VmCodeChunk(ifElse.position) fun translateNonZeroComparison(): VmCodeChunk { val elseBranch = when(ifElse.condition.operator) { @@ -643,7 +641,7 @@ class CodeGen(internal val program: PtProgram, private fun translate(postIncrDecr: PtPostIncrDecr): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(postIncrDecr.position) val operationMem: Opcode val operationRegister: Opcode when(postIncrDecr.operator) { @@ -700,15 +698,15 @@ class CodeGen(internal val program: PtProgram, private fun translate(repeat: PtRepeatLoop): VmCodeChunk { when (constIntValue(repeat.count)) { - 0 -> return VmCodeChunk() - 1 -> return translateGroup(repeat.children) + 0 -> return VmCodeChunk(repeat.position) + 1 -> return translateGroup(repeat.children, repeat.position) 256 -> { // 256 iterations can still be done with just a byte counter if you set it to zero as starting value. repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position) } } - val code = VmCodeChunk() + val code = VmCodeChunk(repeat.position) val counterReg = vmRegisters.nextFree() val vmDt = vmType(repeat.count.type) code += expressionEval.translateExpression(repeat.count, counterReg, -1) @@ -721,7 +719,7 @@ class CodeGen(internal val program: PtProgram, } private fun translate(jump: PtJump): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(jump.position) if(jump.address!=null) throw AssemblyError("cannot jump to memory location in the vm target") code += if(jump.generatedLabel!=null) @@ -733,14 +731,14 @@ class CodeGen(internal val program: PtProgram, return code } - private fun translateGroup(group: List): VmCodeChunk { - val code = VmCodeChunk() + private fun translateGroup(group: List, position: Position): VmCodeChunk { + val code = VmCodeChunk(position) group.forEach { code += translateNode(it) } return code } private fun translate(ret: PtReturn): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(ret.position) val value = ret.value if(value!=null) { // Call Convention: return value is always returned in r0 (or fr0 if float) @@ -753,33 +751,39 @@ class CodeGen(internal val program: PtProgram, return code } - private fun translate(sub: PtSub): VmCodeChunk { - val code = VmCodeChunk() - code += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}") - code += VmCodeLabel(sub.scopedName) + private fun translate(sub: PtSub): VmSubroutine { + val vmsub = VmSubroutine(sub.scopedName, sub.returntype, sub.position) + vmsub += VmCodeLabel(sub.scopedName) for (child in sub.children) { - code += translateNode(child) + vmsub += translateNode(child) } - code += VmCodeComment("SUB-END '${sub.name}'") - return code + return vmsub } - private fun translate(sub: PtAsmSub): VmCodeChunk { - val code = VmCodeChunk() - code += VmCodeComment("ASMSUB: ${sub.scopedName}") - code += VmCodeLabel(sub.scopedName) + private fun translate(sub: PtAsmSub): VmAsmSubroutine { + val vmsub = VmAsmSubroutine(sub.scopedName, sub.position) + vmsub += VmCodeLabel(sub.scopedName) for (child in sub.children) { - code += translateNode(child) + vmsub += translateNode(child) } - code += VmCodeComment("ASMSUB-END '${sub.name}'") - return code + return vmsub } private fun translate(block: PtBlock): VmBlock { - val vmblock = VmBlock(block.name, block.address, block.alignment) // no use for other attributes yet? + val vmblock = VmBlock(block.name, block.address, block.alignment, block.position) // no use for other attributes yet? for (child in block.children) { - if(child !is PtAssignment) // global variable initialization is done elsewhere - vmblock += translateNode(child) + when(child) { + is PtNop -> { /* nothing */ } + is PtAssignment -> { /* global variable initialization is done elsewhere */ } + is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ } + is PtSub -> vmblock += translateNode(child) + is PtAsmSub -> vmblock += translateNode(child) + is PtInlineAssembly -> vmblock += translateNode(child) + else -> { + println("BLOCK: TRANSLATING WEIRD THING $child") + vmblock += translateNode(child) + } + } } return vmblock } diff --git a/codeGenExperimental/src/prog8/codegen/experimental/ExpressionGen.kt b/codeGenExperimental/src/prog8/codegen/experimental/ExpressionGen.kt index 07a82b01c..1a20bc198 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/ExpressionGen.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/ExpressionGen.kt @@ -13,7 +13,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { require(codeGen.vmRegisters.peekNext() > resultRegister) - val code = VmCodeChunk() + val code = VmCodeChunk(expr.position) when (expr) { is PtMachineRegister -> { @@ -73,7 +73,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(check.position) code += translateExpression(check.element, resultRegister, -1) // load the element to check in resultRegister val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable when(iterable.dt) { @@ -106,7 +106,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type) val vmDt = codeGen.vmType(arrayIx.type) - val code = VmCodeChunk() + val code = VmCodeChunk(arrayIx.position) val idxReg = codeGen.vmRegisters.nextFree() val arrayLocation = codeGen.allocations.get(arrayIx.variable.targetName) @@ -131,7 +131,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } else { code += translateExpression(arrayIx.index, idxReg, -1) if(eltSize>1) - code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize) + code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize, arrayIx.position) if(vmDt==VmDataType.FLOAT) code += VmCodeInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, value = arrayLocation) else @@ -141,7 +141,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(expr.position) code += translateExpression(expr.value, resultRegister, -1) val vmDt = codeGen.vmType(expr.type) when(expr.operator) { @@ -159,7 +159,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun translate(cast: PtTypeCast, predefinedResultRegister: Int, predefinedResultFpRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(cast.position) if(cast.type==cast.value.type) return code val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.vmRegisters.nextFreeFloat() @@ -272,7 +272,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { signed: Boolean, greaterEquals: Boolean ): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(vmDt==VmDataType.FLOAT) { val leftFpReg = codeGen.vmRegisters.nextFreeFloat() val rightFpReg = codeGen.vmRegisters.nextFreeFloat() @@ -321,7 +321,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { signed: Boolean, lessEquals: Boolean ): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(vmDt==VmDataType.FLOAT) { val leftFpReg = codeGen.vmRegisters.nextFreeFloat() val rightFpReg = codeGen.vmRegisters.nextFreeFloat() @@ -364,7 +364,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, notEquals: Boolean): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(vmDt==VmDataType.FLOAT) { val leftFpReg = codeGen.vmRegisters.nextFreeFloat() val rightFpReg = codeGen.vmRegisters.nextFreeFloat() @@ -402,7 +402,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(codeGen.isOne(binExpr.right)) { code += translateExpression(binExpr.left, resultRegister, -1) val opc = if (signed) Opcode.ASR else Opcode.LSR @@ -418,7 +418,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorShiftRightInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) if(codeGen.isOne(operand)) { val opc = if (signed) Opcode.ASRM else Opcode.LSRM code += VmCodeInstruction(opc, vmDt, value=address) @@ -432,7 +432,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(codeGen.isOne(binExpr.right)){ code += translateExpression(binExpr.left, resultRegister, -1) code += VmCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister) @@ -446,7 +446,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorShiftLeftInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) if(codeGen.isOne(operand)){ code += VmCodeInstruction(Opcode.LSLM, vmDt, value=address) } else { @@ -458,7 +458,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorXor(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(binExpr.right is PtNumber) { code += translateExpression(binExpr.left, resultRegister, -1) code += VmCodeInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) @@ -472,7 +472,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorXorInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) val operandReg = codeGen.vmRegisters.nextFree() code += translateExpression(operand, operandReg, -1) code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = address) @@ -480,7 +480,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(binExpr.right is PtNumber) { code += translateExpression(binExpr.left, resultRegister, -1) code += VmCodeInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) @@ -494,7 +494,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorAndInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) val operandReg = codeGen.vmRegisters.nextFree() code += translateExpression(operand, operandReg, -1) code += VmCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=address) @@ -502,7 +502,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorOr(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(binExpr.right is PtNumber) { code += translateExpression(binExpr.left, resultRegister, -1) code += VmCodeInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) @@ -516,7 +516,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorOrInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) val operandReg = codeGen.vmRegisters.nextFree() code += translateExpression(operand, operandReg, -1) code += VmCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = address) @@ -526,7 +526,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk { if(vmDt==VmDataType.FLOAT) throw IllegalArgumentException("floating-point modulo not supported") - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) val rightResultReg = codeGen.vmRegisters.nextFree() if(binExpr.right is PtNumber) { code += translateExpression(binExpr.left, resultRegister, -1) @@ -544,13 +544,13 @@ internal class ExpressionGen(private val codeGen: CodeGen) { resultRegister: Int, resultFpRegister: Int, signed: Boolean): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) val constFactorRight = binExpr.right as? PtNumber if(vmDt==VmDataType.FLOAT) { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { code += translateExpression(binExpr.left, -1, resultFpRegister) val factor = constFactorRight.number.toFloat() - code += codeGen.divideByConstFloat(resultFpRegister, factor) + code += codeGen.divideByConstFloat(resultFpRegister, factor, binExpr.position) } else { val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat() code += translateExpression(binExpr.left, -1, resultFpRegister) @@ -564,7 +564,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { code += translateExpression(binExpr.left, resultRegister, -1) val factor = constFactorRight.number.toInt() - code += codeGen.divideByConst(vmDt, resultRegister, factor, signed) + code += codeGen.divideByConst(vmDt, resultRegister, factor, signed, binExpr.position) } else { val rightResultReg = codeGen.vmRegisters.nextFree() if(binExpr.right is PtNumber) { @@ -587,12 +587,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorDivideInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) val constFactorRight = operand as? PtNumber if(vmDt==VmDataType.FLOAT) { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { val factor = constFactorRight.number.toFloat() - code += codeGen.divideByConstFloatInplace(address, factor) + code += codeGen.divideByConstFloatInplace(address, factor, operand.position) } else { val operandFpReg = codeGen.vmRegisters.nextFreeFloat() code += translateExpression(operand, -1, operandFpReg) @@ -604,7 +604,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } else { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { val factor = constFactorRight.number.toInt() - code += codeGen.divideByConstInplace(vmDt, address, factor, signed) + code += codeGen.divideByConstInplace(vmDt, address, factor, signed, operand.position) } else { val operandReg = codeGen.vmRegisters.nextFree() code += translateExpression(operand, operandReg, -1) @@ -618,18 +618,18 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) val constFactorLeft = binExpr.left as? PtNumber val constFactorRight = binExpr.right as? PtNumber if(vmDt==VmDataType.FLOAT) { if(constFactorLeft!=null) { code += translateExpression(binExpr.right, -1, resultFpRegister) val factor = constFactorLeft.number.toFloat() - code += codeGen.multiplyByConstFloat(resultFpRegister, factor) + code += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorLeft.position) } else if(constFactorRight!=null) { code += translateExpression(binExpr.left, -1, resultFpRegister) val factor = constFactorRight.number.toFloat() - code += codeGen.multiplyByConstFloat(resultFpRegister, factor) + code += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorRight.position) } else { val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat() code += translateExpression(binExpr.left, -1, resultFpRegister) @@ -640,11 +640,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) { if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) { code += translateExpression(binExpr.right, resultRegister, -1) val factor = constFactorLeft.number.toInt() - code += codeGen.multiplyByConst(vmDt, resultRegister, factor) + code += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorLeft.position) } else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { code += translateExpression(binExpr.left, resultRegister, -1) val factor = constFactorRight.number.toInt() - code += codeGen.multiplyByConst(vmDt, resultRegister, factor) + code += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorRight.position) } else { val rightResultReg = codeGen.vmRegisters.nextFree() code += translateExpression(binExpr.left, resultRegister, -1) @@ -656,12 +656,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorMultiplyInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) val constFactorRight = operand as? PtNumber if(vmDt==VmDataType.FLOAT) { if(constFactorRight!=null) { val factor = constFactorRight.number.toFloat() - code += codeGen.multiplyByConstFloatInplace(address, factor) + code += codeGen.multiplyByConstFloatInplace(address, factor, constFactorRight.position) } else { val operandFpReg = codeGen.vmRegisters.nextFreeFloat() code += translateExpression(operand, -1, operandFpReg) @@ -670,7 +670,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } else { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { val factor = constFactorRight.number.toInt() - code += codeGen.multiplyByConstInplace(vmDt, address, factor) + code += codeGen.multiplyByConstInplace(vmDt, address, factor, constFactorRight.position) } else { val operandReg = codeGen.vmRegisters.nextFree() code += translateExpression(operand, operandReg, -1) @@ -681,7 +681,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(vmDt==VmDataType.FLOAT) { if((binExpr.right as? PtNumber)?.number==1.0) { code += translateExpression(binExpr.left, -1, resultFpRegister) @@ -719,7 +719,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorMinusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) if(vmDt==VmDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { code += VmCodeInstruction(Opcode.DECM, vmDt, value=address) @@ -743,7 +743,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(binExpr.position) if(vmDt==VmDataType.FLOAT) { if((binExpr.left as? PtNumber)?.number==1.0) { code += translateExpression(binExpr.right, -1, resultFpRegister) @@ -789,7 +789,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } internal fun operatorPlusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { - val code = VmCodeChunk() + val code = VmCodeChunk(operand.position) if(vmDt==VmDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { code += VmCodeInstruction(Opcode.INCM, vmDt, value = address) @@ -815,7 +815,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.functionName)) { is StSub -> { - val code = VmCodeChunk() + val code = VmCodeChunk(fcall.position) for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) { val paramDt = codeGen.vmType(parameter.type) if(codeGen.isZero(arg)) { diff --git a/codeGenExperimental/src/prog8/codegen/experimental/IRPeepholeOptimizer.kt b/codeGenExperimental/src/prog8/codegen/experimental/IRPeepholeOptimizer.kt index 839fcddbf..6bb01900a 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/IRPeepholeOptimizer.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/IRPeepholeOptimizer.kt @@ -7,37 +7,46 @@ import prog8.vm.VmDataType class IRPeepholeOptimizer(private val vmprog: IRProgram) { fun optimize() { - vmprog.getBlocks().forEach { block -> - do { - val indexedInstructions = block.lines.withIndex() - .filter { it.value is VmCodeInstruction } - .map { IndexedValue(it.index, (it.value as VmCodeInstruction).ins) } - val changed = removeNops(block, indexedInstructions) - || removeDoubleLoadsAndStores(block, indexedInstructions) // TODO not yet implemented - || removeUselessArithmetic(block, indexedInstructions) - || removeWeirdBranches(block, indexedInstructions) - || removeDoubleSecClc(block, indexedInstructions) - || cleanupPushPop(block, indexedInstructions) - // TODO other optimizations: - // more complex optimizations such as unused registers - } while(changed) + vmprog.blocks.forEach { block -> + block.children.forEach { child -> + when(child) { + is VmCodeChunk -> { + do { + val indexedInstructions = child.lines.withIndex() + .filter { it.value is VmCodeInstruction } + .map { IndexedValue(it.index, (it.value as VmCodeInstruction).ins) } + val changed = removeNops(child, indexedInstructions) + || removeDoubleLoadsAndStores(child, indexedInstructions) // TODO not yet implemented + || removeUselessArithmetic(child, indexedInstructions) + || removeWeirdBranches(child, indexedInstructions) + || removeDoubleSecClc(child, indexedInstructions) + || cleanupPushPop(child, indexedInstructions) + // TODO other optimizations: + // more complex optimizations such as unused registers + } while (changed) + } + else -> { + TODO("block child $child") + } + } + } } } - private fun cleanupPushPop(block: VmCodeChunk, indexedInstructions: List>): Boolean { + private fun cleanupPushPop(chunk: VmCodeChunk, indexedInstructions: List>): Boolean { // push followed by pop to same target, or different target->replace with load var changed = false indexedInstructions.reversed().forEach { (idx, ins) -> if(ins.opcode==Opcode.PUSH) { - if(idx < block.lines.size-1) { - val insAfter = block.lines[idx+1] as? VmCodeInstruction + if(idx < chunk.lines.size-1) { + val insAfter = chunk.lines[idx+1] as? VmCodeInstruction if(insAfter!=null && insAfter.ins.opcode ==Opcode.POP) { if(ins.reg1==insAfter.ins.reg1) { - block.lines.removeAt(idx) - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) + chunk.lines.removeAt(idx) } else { - block.lines[idx] = VmCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1) - block.lines.removeAt(idx+1) + chunk.lines[idx] = VmCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1) + chunk.lines.removeAt(idx+1) } changed = true } @@ -47,25 +56,24 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) { return changed } - - private fun removeDoubleSecClc(block: VmCodeChunk, indexedInstructions: List>): Boolean { + private fun removeDoubleSecClc(chunk: VmCodeChunk, indexedInstructions: List>): Boolean { // double sec, clc // sec+clc or clc+sec var changed = false indexedInstructions.reversed().forEach { (idx, ins) -> if(ins.opcode==Opcode.SEC || ins.opcode==Opcode.CLC) { - if(idx < block.lines.size-1) { - val insAfter = block.lines[idx+1] as? VmCodeInstruction + if(idx < chunk.lines.size-1) { + val insAfter = chunk.lines[idx+1] as? VmCodeInstruction if(insAfter?.ins?.opcode == ins.opcode) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } else if(ins.opcode==Opcode.SEC && insAfter?.ins?.opcode==Opcode.CLC) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } else if(ins.opcode==Opcode.CLC && insAfter?.ins?.opcode==Opcode.SEC) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } } @@ -74,16 +82,16 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) { return changed } - private fun removeWeirdBranches(block: VmCodeChunk, indexedInstructions: List>): Boolean { + private fun removeWeirdBranches(chunk: VmCodeChunk, indexedInstructions: List>): Boolean { // jump/branch to label immediately below var changed = false indexedInstructions.reversed().forEach { (idx, ins) -> if(ins.opcode==Opcode.JUMP && ins.labelSymbol!=null) { // if jumping to label immediately following this - if(idx < block.lines.size-1) { - val label = block.lines[idx+1] as? VmCodeLabel + if(idx < chunk.lines.size-1) { + val label = chunk.lines[idx+1] as? VmCodeLabel if(label?.name == ins.labelSymbol) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } } @@ -92,54 +100,54 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) { return changed } - private fun removeUselessArithmetic(block: VmCodeChunk, indexedInstructions: List>): Boolean { + private fun removeUselessArithmetic(chunk: VmCodeChunk, indexedInstructions: List>): Boolean { // note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first var changed = false indexedInstructions.reversed().forEach { (idx, ins) -> when (ins.opcode) { Opcode.DIV, Opcode.DIVS, Opcode.MUL, Opcode.MOD -> { if (ins.value == 1) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } } Opcode.ADD, Opcode.SUB -> { if (ins.value == 1) { - block.lines[idx] = VmCodeInstruction( + chunk.lines[idx] = VmCodeInstruction( if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC, ins.type, ins.reg1 ) changed = true } else if (ins.value == 0) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } } Opcode.AND -> { if (ins.value == 0) { - block.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0) + chunk.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0) changed = true } else if (ins.value == 255 && ins.type == VmDataType.BYTE) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } else if (ins.value == 65535 && ins.type == VmDataType.WORD) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } } Opcode.OR -> { if (ins.value == 0) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) { - block.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value) + chunk.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value) changed = true } } Opcode.XOR -> { if (ins.value == 0) { - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) changed = true } } @@ -149,18 +157,18 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) { return changed } - private fun removeNops(block: VmCodeChunk, indexedInstructions: List>): Boolean { + private fun removeNops(chunk: VmCodeChunk, indexedInstructions: List>): Boolean { var changed = false indexedInstructions.reversed().forEach { (idx, ins) -> if (ins.opcode == Opcode.NOP) { changed = true - block.lines.removeAt(idx) + chunk.lines.removeAt(idx) } } return changed } - private fun removeDoubleLoadsAndStores(block: VmCodeChunk, indexedInstructions: List>): Boolean { + private fun removeDoubleLoadsAndStores(chunk: VmCodeChunk, indexedInstructions: List>): Boolean { var changed = false indexedInstructions.forEach { (idx, ins) -> diff --git a/codeGenExperimental/src/prog8/codegen/experimental/IRProgram.kt b/codeGenExperimental/src/prog8/codegen/experimental/IRProgram.kt index acfb7826f..a45cc3032 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/IRProgram.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/IRProgram.kt @@ -20,8 +20,8 @@ class IRProgram(val name: String, private val encoding: IStringEncoding, private val st: SymbolTable) { - private val globalInits = mutableListOf() - private val blocks = mutableListOf() + val globalInits = mutableListOf() + val blocks = mutableListOf() fun writeFile() { val outfile = options.outputDir / ("$name.p8ir") @@ -34,23 +34,52 @@ class IRProgram(val name: String, if(!options.dontReinitGlobals) { // note: this a block of code that loads values and stores them into the global variables to reset their values. - out.write("\n[INITGLOBALS]\n") + out.write("\n\n") globalInits.forEach { out.writeLine(it) } - out.write("[/INITGLOBALS]\n") + out.write("\n") } - out.write("\n[CODE]\n") - blocks.forEach { block -> - out.write("\n[BLOCK NAME=${block.name} ADDRESS=${block.address} ALIGN=${block.alignment}]\n") - block.lines.forEach { out.writeLine(it) } - out.write("[/BLOCK]\n") + out.write("\n\n") + writeBlocks(out) + out.write("\n") + } + } + + private fun writeBlocks(out: BufferedWriter) { + blocks.forEach { block -> + out.write("\n\n") + block.children.forEach { + when(it) { + is VmSubroutine -> { + out.write("\n") + it.lines.forEach { line -> out.writeLine(line) } + out.write("\n") + } + is VmAsmSubroutine -> { + out.write("\n") + it.lines.forEach { line -> out.writeLine(line) } + out.write("\n") + } + is VmInlineAsmChunk -> { + out.write("\n") + it.lines.forEach { line -> out.writeLine(line) } + out.write("\n") + } + is VmCodeChunk -> { + println("GENERIC CHUNK IN BLOCK $it ${it.position}") // TODO must all be VmSubroutine + it.lines.forEach { line -> out.writeLine(line) } + } + else -> { + TODO("BLOCK CHILD $it") + } + } } - out.write("[/CODE]\n") + out.write("\n") } } private fun writeOptions(out: BufferedWriter) { - out.write("[OPTIONS]\n") + out.write("\n") out.write("compTarget = ${options.compTarget.name}\n") out.write("output = ${options.output}\n") out.write("launcher = ${options.launcher}\n") @@ -60,11 +89,11 @@ class IRProgram(val name: String, out.write("dontReinitGlobals = ${options.dontReinitGlobals}\n") out.write("evalStackBaseAddress = ${options.evalStackBaseAddress}\n") // other options not yet useful here? - out.write("[/OPTIONS]\n") + out.write("\n") } private fun writeVariableAllocations(out: Writer) { - out.write("\n[VARIABLES]\n") + out.write("\n\n") for (variable in st.allVariables) { val typeStr = when(variable.dt) { DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte" @@ -100,9 +129,9 @@ class IRProgram(val name: String, // TODO have uninitialized variables? (BSS SECTION) out.write("VAR ${variable.scopedName.joinToString(".")} $typeStr = $value\n") } - out.write("[/VARIABLES]\n") + out.write("\n") - out.write("\n[MEMORYMAPPEDVARIABLES]\n") + out.write("\n\n") for (variable in st.allMemMappedVariables) { val typeStr = when(variable.dt) { DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte" @@ -114,11 +143,11 @@ class IRProgram(val name: String, } out.write("MAP ${variable.scopedName.joinToString(".")} $typeStr ${variable.address}\n") } - out.write("[/MEMORYMAPPEDVARIABLES]\n") + out.write("\n") - out.write("\n[MEMORYSLABS]\n") + out.write("\n\n") st.allMemorySlabs.forEach{ slab -> out.write("SLAB _${slab.name} ${slab.size} ${slab.align}\n") } - out.write("[/MEMORYSLABS]\n") + out.write("\n") } private fun BufferedWriter.writeLine(line: VmCodeLine) { @@ -128,7 +157,7 @@ class IRProgram(val name: String, write(line.ins.toString() + "\n") } is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n") - is VmCodeInlineAsm -> { + is VmInlineAsm -> { // TODO FIXUP ASM SYMBOLS??? write(line.assembly+"\n") } @@ -146,7 +175,6 @@ class IRProgram(val name: String, fun addGlobalInits(chunk: VmCodeChunk) = globalInits.addAll(chunk.lines) fun addBlock(block: VmBlock) = blocks.add(block) - fun getBlocks(): List = blocks } sealed class VmCodeLine @@ -191,18 +219,32 @@ class VmCodeInstruction( } class VmCodeLabel(val name: List): VmCodeLine() -internal class VmCodeComment(val comment: String): VmCodeLine() +class VmCodeComment(val comment: String): VmCodeLine() class VmBlock( val name: String, val address: UInt?, val alignment: PtBlock.BlockAlignment, - initial: VmCodeLine? = null -): VmCodeChunk(initial) + val position: Position +) { + val children = mutableListOf() + operator fun plusAssign(child: VmCodeChunk) { + children += child + } +} -open class VmCodeChunk(initial: VmCodeLine? = null) { +class VmSubroutine(val scopedName: List, + val returnType: DataType?, + position: Position, + initial: VmCodeLine? = null): VmCodeChunk(position, initial) + +class VmAsmSubroutine(val scopedName: List, + position: Position, + initial: VmCodeLine? = null): VmCodeChunk(position, initial) + +open class VmCodeChunk(val position: Position, initial: VmCodeLine? = null) { val lines = mutableListOf() init { @@ -219,9 +261,12 @@ open class VmCodeChunk(initial: VmCodeLine? = null) { } } -internal class VmCodeInlineAsm(asm: String): VmCodeLine() { +class VmInlineAsmChunk(asm: String, position: Position): VmCodeChunk(position, VmInlineAsm(asm)) + + +class VmInlineAsm(asm: String): VmCodeLine() { // TODO INLINE ASSEMBLY IN IL CODE - val assembly: String = "; TODO INLINE ASSMBLY IN IL CODE" // was: asm.trimIndent() + val assembly: String = "; TODO INLINE ASSEMBLY IN IL CODE" // was: asm.trimIndent() } -internal class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine() +class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine() diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 770a3867d..f3e5c38c0 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -445,10 +445,8 @@ internal fun asmGeneratorFor(program: Program, options: CompilationOptions): IAssemblyGenerator { if(options.experimentalCodegen) { - if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) { - val intermediateAst = IntermediateAstMaker(program).transform() - return prog8.codegen.experimental.CodeGen(intermediateAst, symbolTable, options, errors) - } + val intermediateAst = IntermediateAstMaker(program).transform() + return prog8.codegen.experimental.CodeGen(intermediateAst, symbolTable, options, errors) } else { if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) // TODO rewrite 6502 codegen on new Intermediary Ast or on new Intermediate Representation