diff --git a/compilerAst/src/prog8/Either.kt b/codeCore/src/prog8/code/Either.kt similarity index 96% rename from compilerAst/src/prog8/Either.kt rename to codeCore/src/prog8/code/Either.kt index 6e78c7658..9bd88ada6 100644 --- a/compilerAst/src/prog8/Either.kt +++ b/codeCore/src/prog8/code/Either.kt @@ -1,8 +1,7 @@ -package prog8 +package prog8.code /** * By convention, the right side of an `Either` is used to hold successful values. - * */ sealed class Either { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index a5a61ff43..03ffa4efb 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -53,7 +53,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg (sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes) || (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes) - internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) { + internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) { // TODO remove isExpression unused parameter // Output only the code to set up the parameters and perform the actual call // NOTE: does NOT output the code to deal with the result values! // NOTE: does NOT output code to save/restore the X register for this call! Every caller should deal with this in their own way!! diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 6cdea8258..7d5dd693f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -5,14 +5,11 @@ import prog8.code.core.AssemblyError import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.core.SignedDatatypes -import prog8.intermediate.IRCodeChunk -import prog8.intermediate.IRDataType -import prog8.intermediate.IRInstruction -import prog8.intermediate.Opcode +import prog8.intermediate.* internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) { - internal fun translate(assignment: PtAssignment): IRCodeChunk { + internal fun translate(assignment: PtAssignment): IRCodeChunks { if(assignment.target.children.single() is PtMachineRegister) throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister") @@ -22,7 +19,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express translateRegularAssign(assignment) } - private fun translateInplaceAssign(assignment: PtAssignment): IRCodeChunk { + private fun translateInplaceAssign(assignment: PtAssignment): IRCodeChunks { val ident = assignment.target.identifier val memory = assignment.target.memory val array = assignment.target.array @@ -48,23 +45,23 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express address: Int, value: PtExpression, origAssign: PtAssignment - ): IRCodeChunk { + ): IRCodeChunks { val vmDt = codeGen.irType(value.type) - val code = IRCodeChunk(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 PtIdentifier -> return emptyList() // do nothing, x=x null assignment. + is PtMachineRegister -> return emptyList() // do nothing, reg=reg null assignment is PtPrefix -> return inplacePrefix(value.operator, vmDt, address, null, value.position) is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, null, origAssign) is PtMemoryByte -> { return if (!codeGen.options.compTarget.machine.isIOAddress(address.toUInt())) - code // do nothing, mem=mem null assignment. + emptyList() // do nothing, mem=mem null assignment. else { // read and write a (i/o) memory location to itself. val tempReg = codeGen.registers.nextFree() + val code = IRCodeChunk(null, origAssign.position) code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address) code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address) - code + listOf(code) } } else -> return fallbackAssign(origAssign) @@ -75,25 +72,26 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express symbol: String, value: PtExpression, origAssign: PtAssignment - ): IRCodeChunk { + ): IRCodeChunks { val vmDt = codeGen.irType(value.type) - val code = IRCodeChunk(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, null, symbol, value.position) - is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign) + return when(value) { + is PtIdentifier -> emptyList() // do nothing, x=x null assignment. + is PtMachineRegister -> emptyList() // do nothing, reg=reg null assignment + is PtPrefix -> inplacePrefix(value.operator, vmDt, null, symbol, value.position) + is PtBinaryExpression -> inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign) is PtMemoryByte -> { + val code = IRCodeChunk(null, origAssign.position) val tempReg = codeGen.registers.nextFree() code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, labelSymbol = symbol) code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, labelSymbol = symbol) - return code + listOf(code) } - else -> return fallbackAssign(origAssign) + + else -> fallbackAssign(origAssign) } } - private fun fallbackAssign(origAssign: PtAssignment): IRCodeChunk { + private fun fallbackAssign(origAssign: PtAssignment): IRCodeChunks { if (codeGen.options.slowCodegenWarnings) codeGen.errors.warn("indirect code for in-place assignment", origAssign.position) return translateRegularAssign(origAssign) @@ -107,7 +105,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express knownAddress: Int?, symbol: String?, origAssign: PtAssignment - ): IRCodeChunk { + ): IRCodeChunks { if(knownAddress!=null) { when (operator) { "+" -> return expressionEval.operatorPlusInplace(knownAddress, null, vmDt, operand) @@ -139,8 +137,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express return fallbackAssign(origAssign) } - private fun inplacePrefix(operator: String, vmDt: IRDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunk { - val code= IRCodeChunk(position) + private fun inplacePrefix(operator: String, vmDt: IRDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunks { + val code= IRCodeChunk(null, position) when(operator) { "+" -> { } "-" -> { @@ -160,17 +158,16 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } else -> throw AssemblyError("weird prefix operator") } - return code + return listOf(code) } - private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunk { + private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunks { // note: assigning array and string values is done via an explicit memcopy/stringcopy function call. val ident = assignment.target.identifier val memory = assignment.target.memory val array = assignment.target.array val vmDt = codeGen.irType(assignment.value.type) - - val code = IRCodeChunk(assignment.position) + val result = mutableListOf() var resultRegister = -1 var resultFpRegister = -1 val zero = codeGen.isZero(assignment.value) @@ -178,20 +175,20 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express // calculate the assignment value if (vmDt == IRDataType.FLOAT) { resultFpRegister = codeGen.registers.nextFreeFloat() - code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister) + result += expressionEval.translateExpression(assignment.value, -1, resultFpRegister) } else { resultRegister = if (assignment.value is PtMachineRegister) { (assignment.value as PtMachineRegister).register } else { val reg = codeGen.registers.nextFree() - code += expressionEval.translateExpression(assignment.value, reg, -1) + result += expressionEval.translateExpression(assignment.value, reg, -1) reg } } } if(ident!=null) { val symbol = ident.targetName.joinToString(".") - code += if(zero) { + val instruction = if(zero) { IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = symbol) } else { if (vmDt == IRDataType.FLOAT) @@ -199,6 +196,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express else IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = symbol) } + result += IRCodeChunk(null, ident.position).also { it += instruction } + return result } else if(array!=null) { val variable = array.variable.targetName.joinToString(".") @@ -211,84 +210,90 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express if(array.index.type!=DataType.UBYTE) throw AssemblyError("non-array var indexing requires bytes index") val idxReg = codeGen.registers.nextFree() - code += expressionEval.translateExpression(array.index, idxReg, -1) + result += expressionEval.translateExpression(array.index, idxReg, -1) + val code = IRCodeChunk(null, assignment.position) if(zero) { // there's no STOREZIX instruction resultRegister = codeGen.registers.nextFree() code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0) } code += IRInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = variable) - return code + result += code + return result } val fixedIndex = constIntValue(array.index) if(zero) { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - code += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset") + val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset") } + result += chunk } else { val indexReg = codeGen.registers.nextFree() - code += loadIndexReg(array, itemsize, indexReg, array.position) - code += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable) + result += loadIndexReg(array, itemsize, indexReg) + result += IRCodeChunk(null, array.position).also { it += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable) } } } else { if(vmDt== IRDataType.FLOAT) { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - code += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset") + val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset") } + result += chunk } else { val indexReg = codeGen.registers.nextFree() - code += loadIndexReg(array, itemsize, indexReg, array.position) - code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable) + result += loadIndexReg(array, itemsize, indexReg) + result += IRCodeChunk(null, array.position).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable) } } } else { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - code += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset") + val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset") } + result += chunk } else { val indexReg = codeGen.registers.nextFree() - code += loadIndexReg(array, itemsize, indexReg, array.position) - code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable) + result += loadIndexReg(array, itemsize, indexReg) + result += IRCodeChunk(null, array.position).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable) } } } } + return result } else if(memory!=null) { require(vmDt== IRDataType.BYTE) if(zero) { if(memory.address is PtNumber) { - code += IRInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt()) + val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt()) } + result += chunk } else { val addressReg = codeGen.registers.nextFree() - code += expressionEval.translateExpression(memory.address, addressReg, -1) - code += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg) + result += expressionEval.translateExpression(memory.address, addressReg, -1) + result += IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg) } } } else { if(memory.address is PtNumber) { - code += IRInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt()) + val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt()) } + result += chunk } else { val addressReg = codeGen.registers.nextFree() - code += expressionEval.translateExpression(memory.address, addressReg, -1) - code += IRInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg) + result += expressionEval.translateExpression(memory.address, addressReg, -1) + result += IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg) } } } + + return result } else throw AssemblyError("weird assigntarget") - return code } - private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) - if(itemsize==1) { - code += expressionEval.translateExpression(array.index, indexReg, -1) - } - else { + private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int): IRCodeChunks { + return if(itemsize==1) { + expressionEval.translateExpression(array.index, indexReg, -1) + } else { val mult = PtBinaryExpression("*", DataType.UBYTE, array.position) mult.children += array.index mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position) - code += expressionEval.translateExpression(mult, indexReg, -1) + expressionEval.translateExpression(mult, indexReg, -1) } - return code } } \ No newline at end of file diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index 903feb67b..1c5c76a7f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -10,7 +10,7 @@ import prog8.intermediate.* internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGen: ExpressionGen) { - fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { + fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { return when(call.name) { "any" -> funcAny(call, resultRegister) "all" -> funcAll(call, resultRegister) @@ -25,7 +25,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe "rsave", "rsavex", "rrestore", - "rrestorex" -> IRCodeChunk(call.position) // vm doesn't have registers to save/restore + "rrestorex" -> emptyList() // 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") @@ -37,7 +37,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe "peekw" -> funcPeekW(call, resultRegister) "poke" -> funcPoke(call) "pokew" -> funcPokeW(call) - "pokemon" -> IRCodeChunk(call.position) + "pokemon" -> emptyList() "mkword" -> funcMkword(call, resultRegister) "sort" -> funcSort(call) "reverse" -> funcReverse(call) @@ -49,20 +49,21 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } } - private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunks { val leftRegister = codeGen.registers.nextFree() val rightRegister = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args[0], leftRegister, -1) - code += exprGen.translateExpression(call.args[1], rightRegister, -1) - code += IRInstruction(Opcode.CMP, codeGen.irType(call.args[0].type), reg1=leftRegister, reg2=rightRegister) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args[0], leftRegister, -1) + result += exprGen.translateExpression(call.args[1], rightRegister, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.CMP, codeGen.irType(call.args[0].type), reg1=leftRegister, reg2=rightRegister) + } + return result } - private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { + private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable - val code = IRCodeChunk(call.position) val syscall = when (array.dt) { DataType.ARRAY_UB, @@ -72,15 +73,18 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe DataType.ARRAY_F -> IMSyscall.ANY_FLOAT else -> throw IllegalArgumentException("weird type") } - code += exprGen.translateExpression(call.args[0], 0, -1) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) - code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal) - if (resultRegister != 0) - code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args[0], 0, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal) + if (resultRegister != 0) + it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0) + } + return result } - private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { + private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable val syscall = @@ -92,98 +96,116 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe DataType.ARRAY_F -> IMSyscall.ALL_FLOAT else -> throw IllegalArgumentException("weird type") } - val code = IRCodeChunk(call.position) - code += exprGen.translateExpression(call.args[0], 0, -1) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length) - code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal) - if(resultRegister!=0) - code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args[0], 0, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal) + if (resultRegister != 0) + it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0) + } + return result } - private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val sourceDt = call.args.single().type + val result = mutableListOf() if(sourceDt!=DataType.UWORD) { - code += exprGen.translateExpression(call.args[0], resultRegister, -1) + result += exprGen.translateExpression(call.args[0], resultRegister, -1) when (sourceDt) { DataType.UBYTE -> { - code += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1 = resultRegister) + } } DataType.BYTE -> { val notNegativeLabel = codeGen.createLabelName() val compareReg = codeGen.registers.nextFree() - code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=compareReg, reg2=resultRegister) - code += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=compareReg, value=0x80) - code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel) - code += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1=resultRegister) - code += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister) - code += IRCodeLabel(notNegativeLabel) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=compareReg, reg2=resultRegister) + it += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=compareReg, value=0x80) + it += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel) + it += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1=resultRegister) + it += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister) + } + result += IRCodeChunk(notNegativeLabel, call.position) } DataType.WORD -> { val notNegativeLabel = codeGen.createLabelName() val compareReg = codeGen.registers.nextFree() - code += IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1=compareReg, reg2=resultRegister) - code += IRInstruction(Opcode.AND, IRDataType.WORD, reg1=compareReg, value=0x8000) - code += IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel) - code += IRInstruction(Opcode.NEG, IRDataType.WORD, reg1=resultRegister) - code += IRCodeLabel(notNegativeLabel) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1=compareReg, reg2=resultRegister) + it += IRInstruction(Opcode.AND, IRDataType.WORD, reg1=compareReg, value=0x8000) + it += IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel) + it += IRInstruction(Opcode.NEG, IRDataType.WORD, reg1=resultRegister) + } + result += IRCodeChunk(notNegativeLabel, call.position) } else -> throw AssemblyError("weird type") } } - return code + return result } - private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val reg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args.single(), reg, -1) - code += IRInstruction(Opcode.SGN, codeGen.irType(call.type), reg1=resultRegister, reg2=reg) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args.single(), reg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.SGN, codeGen.irType(call.type), reg1 = resultRegister, reg2 = reg) + } + return result } - private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val reg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args.single(), reg, -1) - code += IRInstruction(Opcode.SQRT, IRDataType.WORD, reg1=resultRegister, reg2=reg) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args.single(), reg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.SQRT, IRDataType.WORD, reg1=resultRegister, reg2=reg) + } + return result } - private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunks { + val code = IRCodeChunk(null, call.position) val reg = codeGen.registers.nextFree() code += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=reg) - code += assignRegisterTo(call.args.single(), reg) - return code + val result = mutableListOf(code) + result += assignRegisterTo(call.args.single(), reg) + return result } - private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunks { + val code = IRCodeChunk(null, call.position) val reg = codeGen.registers.nextFree() code += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=reg) - code += assignRegisterTo(call.args.single(), reg) - return code + val result = mutableListOf(code) + result += assignRegisterTo(call.args.single(), reg) + return result } - private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunks { + val result = mutableListOf() val reg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args.single(), reg, -1) - code += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=reg) - return code + result += exprGen.translateExpression(call.args.single(), reg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=reg) + } + return result } - private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunks { + val result = mutableListOf() val reg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args.single(), reg, -1) - code += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=reg) - return code + result += exprGen.translateExpression(call.args.single(), reg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = reg) + } + return result } - private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunk { + private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunks { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable val syscall = @@ -193,14 +215,16 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe DataType.ARRAY_F -> IMSyscall.REVERSE_FLOATS else -> throw IllegalArgumentException("weird type to reverse") } - val code = IRCodeChunk(call.position) - code += exprGen.translateExpression(call.args[0], 0, -1) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length) - code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args[0], 0, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal) + } + return result } - private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunk { + private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunks { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable val syscall = @@ -213,153 +237,184 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported") else -> throw IllegalArgumentException("weird type to sort") } - val code = IRCodeChunk(call.position) - code += exprGen.translateExpression(call.args[0], 0, -1) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length) - code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args[0], 0, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length) + it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal) + } + return result } - private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { + private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val msbReg = codeGen.registers.nextFree() - val code = IRCodeChunk(call.position) - code += exprGen.translateExpression(call.args[0], msbReg, -1) - code += exprGen.translateExpression(call.args[1], resultRegister, -1) - code += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=msbReg) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args[0], msbReg, -1) + result += exprGen.translateExpression(call.args[1], resultRegister, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1 = resultRegister, reg2 = msbReg) + } + return result } - private fun funcPokeW(call: PtBuiltinFunctionCall): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPokeW(call: PtBuiltinFunctionCall): IRCodeChunks { + val result = mutableListOf() if(codeGen.isZero(call.args[1])) { if (call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() - code += IRInstruction(Opcode.STOREZM, IRDataType.WORD, value = address) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREZM, IRDataType.WORD, value = address) + } } else { val addressReg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args[0], addressReg, -1) - code += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg2 = addressReg) + result += exprGen.translateExpression(call.args[0], addressReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg2 = addressReg) + } } } else { val valueReg = codeGen.registers.nextFree() if (call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() - code += exprGen.translateExpression(call.args[1], valueReg, -1) - code += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1 = valueReg, value = address) + result += exprGen.translateExpression(call.args[1], valueReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1 = valueReg, value = address) + } } else { val addressReg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args[0], addressReg, -1) - code += exprGen.translateExpression(call.args[1], valueReg, -1) - code += IRInstruction(Opcode.STOREI, IRDataType.WORD, reg1 = valueReg, reg2 = addressReg) + result += exprGen.translateExpression(call.args[0], addressReg, -1) + result += exprGen.translateExpression(call.args[1], valueReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREI, IRDataType.WORD, reg1 = valueReg, reg2 = addressReg) + } } } - return code + return result } - private fun funcPoke(call: PtBuiltinFunctionCall): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPoke(call: PtBuiltinFunctionCall): IRCodeChunks { + val result = mutableListOf() if(codeGen.isZero(call.args[1])) { if (call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() - code += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, value = address) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, value = address) + } } else { val addressReg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args[0], addressReg, -1) - code += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg2 = addressReg) + result += exprGen.translateExpression(call.args[0], addressReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg2 = addressReg) + } } } else { val valueReg = codeGen.registers.nextFree() if (call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() - code += exprGen.translateExpression(call.args[1], valueReg, -1) - code += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueReg, value = address) + result += exprGen.translateExpression(call.args[1], valueReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueReg, value = address) + } } else { val addressReg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args[0], addressReg, -1) - code += exprGen.translateExpression(call.args[1], valueReg, -1) - code += IRInstruction(Opcode.STOREI, IRDataType.BYTE, reg1 = valueReg, reg2 = addressReg) + result += exprGen.translateExpression(call.args[0], addressReg, -1) + result += exprGen.translateExpression(call.args[1], valueReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.STOREI, IRDataType.BYTE, reg1 = valueReg, reg2 = addressReg) + } } } - return code + return result } - private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() if(call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() - code += IRInstruction(Opcode.LOADM, IRDataType.WORD, reg1 = resultRegister, value = address) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOADM, IRDataType.WORD, reg1 = resultRegister, value = address) + } } else { val addressReg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args.single(), addressReg, -1) - code += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = resultRegister, reg2 = addressReg) + result += exprGen.translateExpression(call.args.single(), addressReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = resultRegister, reg2 = addressReg) + } } - return code + return result } - private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(call.position) + private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() if(call.args[0] is PtNumber) { val address = (call.args[0] as PtNumber).number.toInt() - code += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1 = resultRegister, value = address) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1 = resultRegister, value = address) + } } else { val addressReg = codeGen.registers.nextFree() - code += exprGen.translateExpression(call.args.single(), addressReg, -1) - code += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultRegister, reg2 = addressReg) + result += exprGen.translateExpression(call.args.single(), addressReg, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultRegister, reg2 = addressReg) + } } - return code + return result } - private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunks { + val code = IRCodeChunk(null, position) code += IRInstruction(Opcode.RND, IRDataType.BYTE, reg1=resultRegister) - return code + return listOf(code) } - private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunks { + val code = IRCodeChunk(null, position) code += IRInstruction(Opcode.RND, IRDataType.WORD, reg1=resultRegister) - return code + return listOf(code) } - private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { + private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val name = (call.args[0] as PtString).value - val code = IRCodeChunk(call.position) + val code = IRCodeChunk(null, call.position) code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultRegister, labelSymbol = "prog8_slabs.prog8_memoryslab_$name") - return code + return listOf(code) } - private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(call.position) - code += exprGen.translateExpression(call.args.single(), resultRegister, -1) + private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { + return 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): IRCodeChunk { - val code = IRCodeChunk(call.position) - code += exprGen.translateExpression(call.args.single(), resultRegister, -1) - code += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultRegister, reg2=resultRegister) + private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() + result += exprGen.translateExpression(call.args.single(), resultRegister, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(Opcode.MSIG, IRDataType.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. - return code + return result } - private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk { + private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks { val vmDt = codeGen.irType(call.args[0].type) - val code = IRCodeChunk(call.position) - code += exprGen.translateExpression(call.args[0], resultRegister, -1) - code += IRInstruction(opcode, vmDt, reg1=resultRegister) - code += assignRegisterTo(call.args[0], resultRegister) - return code + val result = mutableListOf() + result += exprGen.translateExpression(call.args[0], resultRegister, -1) + result += IRCodeChunk(null, call.position).also { + it += IRInstruction(opcode, vmDt, reg1 = resultRegister) + } + result += assignRegisterTo(call.args[0], resultRegister) + return result } - private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunk { - val code = IRCodeChunk(target.position) + private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunks { + val code = IRCodeChunk(null, target.position) val assignment = PtAssignment(target.position) val assignTarget = PtAssignTarget(target.position) assignTarget.children.add(target) assignment.children.add(assignTarget) assignment.children.add(PtMachineRegister(register, target.type, target.position)) - code += codeGen.translateNode(assignment) - return code + val result = mutableListOf(code) + result += codeGen.translateNode(assignment) + return result } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index ba500a112..e2c387200 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -9,28 +9,33 @@ import prog8.intermediate.* internal class ExpressionGen(private val codeGen: IRCodeGen) { - fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { + fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { require(codeGen.registers.peekNext() > resultRegister) - val code = IRCodeChunk(expr.position) - - when (expr) { + return when (expr) { is PtMachineRegister -> { if(resultRegister!=expr.register) { val vmDt = codeGen.irType(expr.type) + val code = IRCodeChunk(null, expr.position) code += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register) + listOf(code) + } else { + emptyList() } } is PtNumber -> { val vmDt = codeGen.irType(expr.type) + val code = IRCodeChunk(null, expr.position) code += if(vmDt==IRDataType.FLOAT) IRInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, fpValue = expr.number.toFloat()) else IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt()) + listOf(code) } is PtIdentifier -> { val vmDt = codeGen.irType(expr.type) val symbol = expr.targetName.joinToString(".") + val code = IRCodeChunk(null, expr.position) code += if (expr.type in PassByValueDatatypes) { if(vmDt==IRDataType.FLOAT) IRInstruction(Opcode.LOADM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol) @@ -40,73 +45,92 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { // for strings and arrays etc., load the *address* of the value instead IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol) } + listOf(code) } is PtAddressOf -> { val vmDt = codeGen.irType(expr.type) val symbol = expr.identifier.targetName.joinToString(".") // note: LOAD gets you the address of the symbol, whereas LOADM would get you the value stored at that location + val code = IRCodeChunk(null, expr.position) code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol) + listOf(code) } is PtMemoryByte -> { + val code = IRCodeChunk(null, expr.position) + val result = mutableListOf(code) if(expr.address is PtNumber) { val address = (expr.address as PtNumber).number.toInt() - code += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, value = address) + addInstr(result, IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, value = address), null, expr.position) } else { val addressRegister = codeGen.registers.nextFree() - code += translateExpression(expr.address, addressRegister, -1) - code += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1=resultRegister, reg2=addressRegister) + result += translateExpression(expr.address, addressRegister, -1) + addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1=resultRegister, reg2=addressRegister), null, expr.position) } + result + } + is PtTypeCast -> { + translate(expr, resultRegister, resultFpRegister) + } + is PtPrefix -> { + translate(expr, resultRegister) + } + is PtArrayIndexer -> { + translate(expr, resultRegister, resultFpRegister) + } + is PtBinaryExpression -> { + translate(expr, resultRegister, resultFpRegister) + } + is PtBuiltinFunctionCall -> { + codeGen.translateBuiltinFunc(expr, resultRegister) + } + is PtFunctionCall -> { + translate(expr, resultRegister, resultFpRegister) + } + is PtContainmentCheck -> { + translate(expr, resultRegister, resultFpRegister) } - is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister) - is PtPrefix -> code += translate(expr, resultRegister) - is PtArrayIndexer -> code += translate(expr, resultRegister, resultFpRegister) - is PtBinaryExpression -> code += translate(expr, resultRegister, resultFpRegister) - is PtBuiltinFunctionCall -> code += codeGen.translateBuiltinFunc(expr, resultRegister) - is PtFunctionCall -> code += translate(expr, resultRegister, resultFpRegister) - is PtContainmentCheck -> code += translate(expr, resultRegister, resultFpRegister) is PtRange, is PtArray, is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression") else -> throw AssemblyError("weird expression") } - return code } - private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { - val code = IRCodeChunk(check.position) - code += translateExpression(check.element, resultRegister, -1) // load the element to check in resultRegister + private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { + val result = mutableListOf() + result += 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) { DataType.STR -> { val call = PtFunctionCall(listOf("prog8_lib", "string_contains"), false, DataType.UBYTE, check.position) call.children.add(check.element) call.children.add(check.iterable) - code += translate(call, resultRegister, resultFpRegister) + result += translate(call, resultRegister, resultFpRegister) } DataType.ARRAY_UB, DataType.ARRAY_B -> { val call = PtFunctionCall(listOf("prog8_lib", "bytearray_contains"), false, DataType.UBYTE, check.position) call.children.add(check.element) call.children.add(check.iterable) call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position)) - code += translate(call, resultRegister, resultFpRegister) + result += translate(call, resultRegister, resultFpRegister) } DataType.ARRAY_UW, DataType.ARRAY_W -> { val call = PtFunctionCall(listOf("prog8_lib", "wordarray_contains"), false, DataType.UBYTE, check.position) call.children.add(check.element) call.children.add(check.iterable) call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position)) - code += translate(call, resultRegister, resultFpRegister) + result += translate(call, resultRegister, resultFpRegister) } DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported") else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}") } - return code + return result } - private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { + private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type) val vmDt = codeGen.irType(arrayIx.type) - val code = IRCodeChunk(arrayIx.position) + val result = mutableListOf() val idxReg = codeGen.registers.nextFree() val arrayVarSymbol = arrayIx.variable.targetName.joinToString(".") @@ -116,71 +140,69 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { throw AssemblyError("non-array var indexing requires bytes dt") if(arrayIx.index.type!=DataType.UBYTE) throw AssemblyError("non-array var indexing requires bytes index") - code += translateExpression(arrayIx.index, idxReg, -1) - code += IRInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol) - return code + result += translateExpression(arrayIx.index, idxReg, -1) + addInstr(result, IRInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol), null, arrayIx.position) + return result } if(arrayIx.index is PtNumber) { val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString() if(vmDt==IRDataType.FLOAT) - code += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol = "$arrayVarSymbol+$memOffset") + addInstr(result, IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol = "$arrayVarSymbol+$memOffset"), null, arrayIx.position) else - code += IRInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, labelSymbol = "$arrayVarSymbol+$memOffset") + addInstr(result, IRInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, labelSymbol = "$arrayVarSymbol+$memOffset"), null, arrayIx.position) } else { - code += translateExpression(arrayIx.index, idxReg, -1) + result += translateExpression(arrayIx.index, idxReg, -1) if(eltSize>1) - code += codeGen.multiplyByConst(IRDataType.BYTE, idxReg, eltSize, arrayIx.position) + result += codeGen.multiplyByConst(IRDataType.BYTE, idxReg, eltSize, arrayIx.position) if(vmDt==IRDataType.FLOAT) - code += IRInstruction(Opcode.LOADX, IRDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, labelSymbol = arrayVarSymbol) + addInstr(result, IRInstruction(Opcode.LOADX, IRDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, labelSymbol = arrayVarSymbol), null, arrayIx.position) else - code += IRInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol) + addInstr(result, IRInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol), null, arrayIx.position) } - return code + return result } - private fun translate(expr: PtPrefix, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(expr.position) - code += translateExpression(expr.value, resultRegister, -1) + private fun translate(expr: PtPrefix, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() + result += translateExpression(expr.value, resultRegister, -1) val vmDt = codeGen.irType(expr.type) when(expr.operator) { "+" -> { } - "-" -> { - code += IRInstruction(Opcode.NEG, vmDt, reg1=resultRegister) - } + "-" -> addInstr(result, IRInstruction(Opcode.NEG, vmDt, reg1 = resultRegister), null, expr.position) "~" -> { val mask = if(vmDt==IRDataType.BYTE) 0x00ff else 0xffff - code += IRInstruction(Opcode.XOR, vmDt, reg1=resultRegister, value=mask) + addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value = mask), null, expr.position) } else -> throw AssemblyError("weird prefix operator") } - return code + return result } - private fun translate(cast: PtTypeCast, predefinedResultRegister: Int, predefinedResultFpRegister: Int): IRCodeChunk { - val code = IRCodeChunk(cast.position) + private fun translate(cast: PtTypeCast, predefinedResultRegister: Int, predefinedResultFpRegister: Int): IRCodeChunks { if(cast.type==cast.value.type) - return code + return emptyList() + val result = mutableListOf() val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.registers.nextFreeFloat() val actualResultReg = if(predefinedResultRegister>=0) predefinedResultRegister else codeGen.registers.nextFree() if(cast.value.type==DataType.FLOAT) { // a cast from float to integer, so evaluate the value into a float register first - code += translateExpression(cast.value, -1, actualResultFpReg) + result += translateExpression(cast.value, -1, actualResultFpReg) } else - code += translateExpression(cast.value, actualResultReg, -1) + result += translateExpression(cast.value, actualResultReg, -1) when(cast.type) { DataType.UBYTE -> { when(cast.value.type) { DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ } - DataType.FLOAT -> code += IRInstruction(Opcode.FTOUB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) + DataType.FLOAT -> addInstr(result, IRInstruction(Opcode.FTOUB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg), null, cast.position) else -> throw AssemblyError("weird cast value type") } } DataType.BYTE -> { when(cast.value.type) { DataType.UBYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ } - DataType.FLOAT -> code += IRInstruction(Opcode.FTOSB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) + DataType.FLOAT -> addInstr(result, IRInstruction(Opcode.FTOSB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg), null, cast.position) else -> throw AssemblyError("weird cast value type") } } @@ -188,15 +210,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { when(cast.value.type) { DataType.BYTE -> { // byte -> uword: sign extend - code += IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg) + addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg), null, cast.position) } DataType.UBYTE -> { // ubyte -> uword: sign extend - code += IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg) + addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg), null, cast.position) } DataType.WORD -> { } DataType.FLOAT -> { - code += IRInstruction(Opcode.FTOUW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) + addInstr(result, IRInstruction(Opcode.FTOUW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg), null, cast.position) } else -> throw AssemblyError("weird cast value type") } @@ -205,42 +227,35 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { when(cast.value.type) { DataType.BYTE -> { // byte -> word: sign extend - code += IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg) + addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg), null, cast.position) } DataType.UBYTE -> { // byte -> word: sign extend - code += IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg) + addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg), null, cast.position) } DataType.UWORD -> { } DataType.FLOAT -> { - code += IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) + addInstr(result, IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg), null, cast.position) } else -> throw AssemblyError("weird cast value type") } } DataType.FLOAT -> { - code += when(cast.value.type) { - DataType.UBYTE -> { - IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) - } - DataType.BYTE -> { - IRInstruction(Opcode.FFROMSB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) - } - DataType.UWORD -> { - IRInstruction(Opcode.FFROMUW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) - } - DataType.WORD -> { - IRInstruction(Opcode.FFROMSW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) - } + val instr = when(cast.value.type) { + DataType.UBYTE -> IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) + DataType.BYTE -> IRInstruction(Opcode.FFROMSB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) + DataType.UWORD -> IRInstruction(Opcode.FFROMUW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) + DataType.WORD -> IRInstruction(Opcode.FFROMSW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg) else -> throw AssemblyError("weird cast value type") } + addInstr(result, instr, null, cast.position) } else -> throw AssemblyError("weird cast type") } - return code + return result } - private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { + private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { val vmDt = codeGen.irType(binExpr.left.type) val signed = binExpr.left.type in SignedDatatypes return when(binExpr.operator) { @@ -270,47 +285,48 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { resultRegister: Int, signed: Boolean, greaterEquals: Boolean - ): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + ): IRCodeChunks { + val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { val leftFpReg = codeGen.registers.nextFreeFloat() val rightFpReg = codeGen.registers.nextFreeFloat() val zeroRegister = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, -1, leftFpReg) - code += translateExpression(binExpr.right, -1, rightFpReg) - code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0) + result += translateExpression(binExpr.left, -1, leftFpReg) + result += translateExpression(binExpr.right, -1, rightFpReg) + addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg), null, binExpr.position) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0), null, binExpr.position) val ins = if (signed) { if (greaterEquals) Opcode.SGES else Opcode.SGTS } else { if (greaterEquals) Opcode.SGE else Opcode.SGT } - code += IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister) + addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null, binExpr.position) } else { if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) { val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY) comparisonCall.children.add(binExpr.left) comparisonCall.children.add(binExpr.right) - code += translate(comparisonCall, resultRegister, -1) + result += translate(comparisonCall, resultRegister, -1) val zeroRegister = codeGen.registers.nextFree() - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0) - code += if(greaterEquals) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0), null, binExpr.position) + val instr = if(greaterEquals) IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister) else IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister) + addInstr(result, instr, null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) val ins = if (signed) { if (greaterEquals) Opcode.SGES else Opcode.SGTS } else { if (greaterEquals) Opcode.SGE else Opcode.SGT } - code += IRInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + addInstr(result, IRInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } } - return code + return result } private fun operatorLessThan( @@ -319,303 +335,314 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { resultRegister: Int, signed: Boolean, lessEquals: Boolean - ): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + ): IRCodeChunks { + val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { val leftFpReg = codeGen.registers.nextFreeFloat() val rightFpReg = codeGen.registers.nextFreeFloat() val zeroRegister = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, -1, leftFpReg) - code += translateExpression(binExpr.right, -1, rightFpReg) - code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0) + result += translateExpression(binExpr.left, -1, leftFpReg) + result += translateExpression(binExpr.right, -1, rightFpReg) + addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg), null, binExpr.position) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0), null, binExpr.position) val ins = if (signed) { if (lessEquals) Opcode.SLES else Opcode.SLTS } else { if (lessEquals) Opcode.SLE else Opcode.SLT } - code += IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister) + addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null, binExpr.position) } else { if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) { val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY) comparisonCall.children.add(binExpr.left) comparisonCall.children.add(binExpr.right) - code += translate(comparisonCall, resultRegister, -1) + result += translate(comparisonCall, resultRegister, -1) val zeroRegister = codeGen.registers.nextFree() - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0) - code += if(lessEquals) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0), null, binExpr.position) + val ins = if(lessEquals) IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister) else IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister) + addInstr(result, ins, null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) val ins = if (signed) { if (lessEquals) Opcode.SLES else Opcode.SLTS } else { if (lessEquals) Opcode.SLE else Opcode.SLT } - code += IRInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + addInstr(result, IRInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } } - return code + return result } - private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, notEquals: Boolean): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, notEquals: Boolean): IRCodeChunks { + val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { val leftFpReg = codeGen.registers.nextFreeFloat() val rightFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(binExpr.left, -1, leftFpReg) - code += translateExpression(binExpr.right, -1, rightFpReg) + result += translateExpression(binExpr.left, -1, leftFpReg) + result += translateExpression(binExpr.right, -1, rightFpReg) if (notEquals) { - code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg) + addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg), null, binExpr.position) } else { val label = codeGen.createLabelName() val valueReg = codeGen.registers.nextFree() - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=1) - code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg) - code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=valueReg, labelSymbol = label) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=0) - code += IRCodeLabel(label) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=1), null, binExpr.position) + addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg), null, binExpr.position) + addInstr(result, IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=valueReg, labelSymbol = label), null, binExpr.position) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=0), null, binExpr.position) + result += IRCodeChunk(label, binExpr.position) } } else { if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) { val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY) comparisonCall.children.add(binExpr.left) comparisonCall.children.add(binExpr.right) - code += translate(comparisonCall, resultRegister, -1) + result += translate(comparisonCall, resultRegister, -1) if(!notEquals) - code += IRInstruction(Opcode.INV, vmDt, reg1=resultRegister) - code += IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1) + addInstr(result, IRInstruction(Opcode.INV, vmDt, reg1=resultRegister), null, binExpr.position) + addInstr(result, IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) val opcode = if (notEquals) Opcode.SNE else Opcode.SEQ - code += IRInstruction(opcode, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + addInstr(result, IRInstruction(opcode, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } } - return code + return result } - private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, signed: Boolean): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, signed: Boolean): IRCodeChunks { + val result = mutableListOf() if(codeGen.isOne(binExpr.right)) { - code += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.left, resultRegister, -1) val opc = if (signed) Opcode.ASR else Opcode.LSR - code += IRInstruction(opc, vmDt, reg1 = resultRegister) + addInstr(result, IRInstruction(opc, vmDt, reg1 = resultRegister), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) val opc = if (signed) Opcode.ASRN else Opcode.LSRN - code += IRInstruction(opc, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + addInstr(result, IRInstruction(opc, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } - return code + return result } - internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() if(codeGen.isOne(operand)) { val opc = if (signed) Opcode.ASRM else Opcode.LSRM - code += if(knownAddress!=null) + val ins = if(knownAddress!=null) IRInstruction(opc, vmDt, value=knownAddress) else IRInstruction(opc, vmDt, labelSymbol = symbol) + addInstr(result, ins, null, operand.position) } else { val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) + result += translateExpression(operand, operandReg, -1) val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM - code += if(knownAddress!=null) + val ins = if(knownAddress!=null) IRInstruction(opc, vmDt, reg1 = operandReg, value=knownAddress) else IRInstruction(opc, vmDt, reg1 = operandReg, labelSymbol = symbol) + addInstr(result, ins, null, operand.position) } - return code + return result } - private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() if(codeGen.isOne(binExpr.right)){ - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.LSL, vmDt, reg1=resultRegister) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.LSL, vmDt, reg1=resultRegister), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg), null, binExpr.position) } - return code + return result } - internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() if(codeGen.isOne(operand)){ - code += if(knownAddress!=null) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.LSLM, vmDt, value=knownAddress) else IRInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol) + , null, operand.position) } else { val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(knownAddress!=null) + result += translateExpression(operand, operandReg, -1) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, value=knownAddress) else IRInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, labelSymbol = symbol) + ,null, operand.position) } - return code + return result } - private fun operatorXor(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorXor(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } - return code + return result } - internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(knownAddress!=null) + result += translateExpression(operand, operandReg, -1) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = knownAddress) else IRInstruction(Opcode.XORM, vmDt, reg1=operandReg, labelSymbol = symbol) - return code + ,null, operand.position) + return result } - private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } - return code + return result } - internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(knownAddress!=null) + result += translateExpression(operand, operandReg, -1) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=knownAddress) else IRInstruction(Opcode.ANDM, vmDt, reg1=operandReg, labelSymbol = symbol) - return code + ,null, operand.position) + return result } - private fun operatorOr(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorOr(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunks { + val result = mutableListOf() if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } - return code + return result } - internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(knownAddress!=null) + result += translateExpression(operand, operandReg, -1) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = knownAddress) else IRInstruction(Opcode.ORM, vmDt, reg1=operandReg, labelSymbol = symbol) - return code + , null, operand.position) + return result } - private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk { + private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunks { require(vmDt!=IRDataType.FLOAT) {"floating-point modulo not supported"} - val code = IRCodeChunk(binExpr.position) + val result = mutableListOf() val rightResultReg = codeGen.registers.nextFree() if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()), null, binExpr.position) } else { - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.MODR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.MODR, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } - return code + return result } private fun operatorDivide(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int, - signed: Boolean): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + signed: Boolean): IRCodeChunks { + val result = mutableListOf() val constFactorRight = binExpr.right as? PtNumber if(vmDt==IRDataType.FLOAT) { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { - code += translateExpression(binExpr.left, -1, resultFpRegister) + result += translateExpression(binExpr.left, -1, resultFpRegister) val factor = constFactorRight.number.toFloat() - code += codeGen.divideByConstFloat(resultFpRegister, factor, binExpr.position) + result += codeGen.divideByConstFloat(resultFpRegister, factor, binExpr.position) } else { val rightResultFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += translateExpression(binExpr.right, -1, rightResultFpReg) - code += if(signed) + result += translateExpression(binExpr.left, -1, resultFpRegister) + result += translateExpression(binExpr.right, -1, rightResultFpReg) + addInstr(result, if(signed) IRInstruction(Opcode.DIVSR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg) else IRInstruction(Opcode.DIVR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg) + , null, binExpr.position) } } else { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { - code += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.left, resultRegister, -1) val factor = constFactorRight.number.toInt() - code += codeGen.divideByConst(vmDt, resultRegister, factor, signed, binExpr.position) + result += codeGen.divideByConst(vmDt, resultRegister, factor, signed, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += if (signed) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, if (signed) IRInstruction(Opcode.DIVS, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) else IRInstruction(Opcode.DIV, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) + , null, binExpr.position) } else { - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += if (signed) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, if (signed) IRInstruction(Opcode.DIVSR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) else IRInstruction(Opcode.DIVR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + , null, binExpr.position) } } } - return code + return result } - internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() val constFactorRight = operand as? PtNumber if(vmDt==IRDataType.FLOAT) { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { val factor = constFactorRight.number.toFloat() - code += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor, operand.position) + result += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor, operand.position) } else { val operandFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(operand, -1, operandFpReg) - code += if(signed) { + result += translateExpression(operand, -1, operandFpReg) + val ins = if(signed) { if(knownAddress!=null) IRInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, value = knownAddress) else @@ -627,15 +654,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { else IRInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol) } + addInstr(result, ins, null, operand.position) } } else { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { val factor = constFactorRight.number.toInt() - code += codeGen.divideByConstInplace(vmDt, knownAddress, symbol, factor, signed, operand.position) + result += codeGen.divideByConstInplace(vmDt, knownAddress, symbol, factor, signed, operand.position) } else { val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(signed) { + result += translateExpression(operand, operandReg, -1) + val ins = if(signed) { if(knownAddress!=null) IRInstruction(Opcode.DIVSM, vmDt, reg1 = operandReg, value = knownAddress) else @@ -647,287 +675,298 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { else IRInstruction(Opcode.DIVM, vmDt, reg1 = operandReg, labelSymbol = symbol) } + addInstr(result, ins, null, operand.position) } } - return code + return result } - private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { + val result = mutableListOf() val constFactorLeft = binExpr.left as? PtNumber val constFactorRight = binExpr.right as? PtNumber if(vmDt==IRDataType.FLOAT) { if(constFactorLeft!=null) { - code += translateExpression(binExpr.right, -1, resultFpRegister) + result += translateExpression(binExpr.right, -1, resultFpRegister) val factor = constFactorLeft.number.toFloat() - code += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorLeft.position) + result += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorLeft.position) } else if(constFactorRight!=null) { - code += translateExpression(binExpr.left, -1, resultFpRegister) + result += translateExpression(binExpr.left, -1, resultFpRegister) val factor = constFactorRight.number.toFloat() - code += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorRight.position) + result += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorRight.position) } else { val rightResultFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += translateExpression(binExpr.right, -1, rightResultFpReg) - code += IRInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg) + result += translateExpression(binExpr.left, -1, resultFpRegister) + result += translateExpression(binExpr.right, -1, rightResultFpReg) + addInstr(result, IRInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg), null, binExpr.position) } } else { if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) { - code += translateExpression(binExpr.right, resultRegister, -1) + result += translateExpression(binExpr.right, resultRegister, -1) val factor = constFactorLeft.number.toInt() - code += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorLeft.position) + result += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorLeft.position) } else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { - code += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.left, resultRegister, -1) val factor = constFactorRight.number.toInt() - code += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorRight.position) + result += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorRight.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } } - return code + return result } - internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() val constFactorRight = operand as? PtNumber if(vmDt==IRDataType.FLOAT) { if(constFactorRight!=null) { val factor = constFactorRight.number.toFloat() - code += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor, constFactorRight.position) + result += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor, constFactorRight.position) } else { val operandFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(operand, -1, operandFpReg) - code += if(knownAddress!=null) + result += translateExpression(operand, -1, operandFpReg) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = knownAddress) else IRInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol) + , null, operand.position) } } else { if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { val factor = constFactorRight.number.toInt() - code += codeGen.multiplyByConstInplace(vmDt, knownAddress, symbol, factor, constFactorRight.position) + result += codeGen.multiplyByConstInplace(vmDt, knownAddress, symbol, factor, constFactorRight.position) } else { val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(knownAddress!=null) + result += translateExpression(operand, operandReg, -1) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = knownAddress) else IRInstruction(Opcode.MULM, vmDt, reg1=operandReg, labelSymbol = symbol) + , null, operand.position) } } - return code + return result } - private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { + val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { if((binExpr.right as? PtNumber)?.number==1.0) { - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += IRInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister) + result += translateExpression(binExpr.left, -1, resultFpRegister) + addInstr(result, IRInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister), null, binExpr.position) } else { if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += IRInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat()) + result += translateExpression(binExpr.left, -1, resultFpRegister) + addInstr(result, IRInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat()), null, binExpr.position) } else { val rightResultFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += translateExpression(binExpr.right, -1, rightResultFpReg) - code += IRInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg) + result += translateExpression(binExpr.left, -1, resultFpRegister) + result += translateExpression(binExpr.right, -1, rightResultFpReg) + addInstr(result, IRInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg), null, binExpr.position) } } } else { if((binExpr.right as? PtNumber)?.number==1.0) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.DEC, vmDt, reg1=resultRegister) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.DEC, vmDt, reg1=resultRegister), null, binExpr.position) } else { if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt()) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt()), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } } } - return code + return result } - internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { - code += if(knownAddress!=null) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.DECM, vmDt, value=knownAddress) else IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol) + , null, operand.position) } else { val operandFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(operand, -1, operandFpReg) - code += if(knownAddress!=null) + result += translateExpression(operand, -1, operandFpReg) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=knownAddress) else IRInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol) + , null, operand.position) } } else { if((operand as? PtNumber)?.number==1.0) { - code += if(knownAddress!=null) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.DECM, vmDt, value=knownAddress) else IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol) + , null, operand.position) } else { val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(knownAddress!=null) + result += translateExpression(operand, operandReg, -1) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = knownAddress) else IRInstruction(Opcode.SUBM, vmDt, reg1=operandReg, labelSymbol = symbol) + , null, operand.position) } } - return code + return result } - private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { - val code = IRCodeChunk(binExpr.position) + private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { + val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { if((binExpr.left as? PtNumber)?.number==1.0) { - code += translateExpression(binExpr.right, -1, resultFpRegister) - code += IRInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister) + result += translateExpression(binExpr.right, -1, resultFpRegister) + addInstr(result, IRInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister), null, binExpr.position) } else if((binExpr.right as? PtNumber)?.number==1.0) { - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += IRInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister) + result += translateExpression(binExpr.left, -1, resultFpRegister) + addInstr(result, IRInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister), null, binExpr.position) } else { if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += IRInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat()) + result += translateExpression(binExpr.left, -1, resultFpRegister) + addInstr(result, IRInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat()), null, binExpr.position) } else { val rightResultFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(binExpr.left, -1, resultFpRegister) - code += translateExpression(binExpr.right, -1, rightResultFpReg) - code += IRInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg) + result += translateExpression(binExpr.left, -1, resultFpRegister) + result += translateExpression(binExpr.right, -1, rightResultFpReg) + addInstr(result, IRInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg), null, binExpr.position) } } } else { if((binExpr.left as? PtNumber)?.number==1.0) { - code += translateExpression(binExpr.right, resultRegister, -1) - code += IRInstruction(Opcode.INC, vmDt, reg1=resultRegister) + result += translateExpression(binExpr.right, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.INC, vmDt, reg1=resultRegister), null, binExpr.position) } else if((binExpr.right as? PtNumber)?.number==1.0) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.INC, vmDt, reg1=resultRegister) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.INC, vmDt, reg1=resultRegister), null, binExpr.position) } else { if(binExpr.right is PtNumber) { - code += translateExpression(binExpr.left, resultRegister, -1) - code += IRInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()) + result += translateExpression(binExpr.left, resultRegister, -1) + addInstr(result, IRInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt()), null, binExpr.position) } else { val rightResultReg = codeGen.registers.nextFree() - code += translateExpression(binExpr.left, resultRegister, -1) - code += translateExpression(binExpr.right, rightResultReg, -1) - code += IRInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg) + result += translateExpression(binExpr.left, resultRegister, -1) + result += translateExpression(binExpr.right, rightResultReg, -1) + addInstr(result, IRInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg), null, binExpr.position) } } } - return code + return result } - internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk { - val code = IRCodeChunk(operand.position) + internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { - code += if(knownAddress!=null) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.INCM, vmDt, value = knownAddress) else IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) + , null, operand.position) } else { val operandFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(operand, -1, operandFpReg) - code += if(knownAddress!=null) + result += translateExpression(operand, -1, operandFpReg) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value = knownAddress) else IRInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol) + , null, operand.position) } } else { if((operand as? PtNumber)?.number==1.0) { - code += if(knownAddress!=null) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.INCM, vmDt, value = knownAddress) else IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) + , null, operand.position) } else { val operandReg = codeGen.registers.nextFree() - code += translateExpression(operand, operandReg, -1) - code += if(knownAddress!=null) + result += translateExpression(operand, operandReg, -1) + addInstr(result, if(knownAddress!=null) IRInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=knownAddress) else IRInstruction(Opcode.ADDM, vmDt, reg1=operandReg, labelSymbol = symbol) + , null, operand.position) } } - return code + return result } - fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): IRCodeChunk { + fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): IRCodeChunks { when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.functionName)) { is StSub -> { - val code = IRCodeChunk(fcall.position) + val result = mutableListOf() for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) { val paramDt = codeGen.irType(parameter.type) val symbol = (fcall.functionName + parameter.name).joinToString(".") if(codeGen.isZero(arg)) { - code += IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol) + addInstr(result, IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol), null, fcall.position) } else { if (paramDt == IRDataType.FLOAT) { val argFpReg = codeGen.registers.nextFreeFloat() - code += translateExpression(arg, -1, argFpReg) - code += IRInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, labelSymbol = symbol) + result += translateExpression(arg, -1, argFpReg) + addInstr(result, IRInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, labelSymbol = symbol), null, fcall.position) } else { val argReg = codeGen.registers.nextFree() - code += translateExpression(arg, argReg, -1) - code += IRInstruction(Opcode.STOREM, paramDt, reg1 = argReg, labelSymbol = symbol) + result += translateExpression(arg, argReg, -1) + addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1 = argReg, labelSymbol = symbol), null, fcall.position) } } } - code += IRInstruction(Opcode.CALL, labelSymbol=fcall.functionName.joinToString(".")) + addInstr(result, IRInstruction(Opcode.CALL, labelSymbol=fcall.functionName.joinToString(".")), null, fcall.position) if(fcall.type==DataType.FLOAT) { if (!fcall.void && resultFpRegister != 0) { // Call convention: result value is in fr0, so put it in the required register instead. - code += IRInstruction(Opcode.LOADR, IRDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0) + addInstr(result, IRInstruction(Opcode.LOADR, IRDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0), null, fcall.position) } } else { if (!fcall.void && resultRegister != 0) { // Call convention: result value is in r0, so put it in the required register instead. - code += IRInstruction(Opcode.LOADR, codeGen.irType(fcall.type), reg1 = resultRegister, reg2 = 0) + addInstr(result, IRInstruction(Opcode.LOADR, codeGen.irType(fcall.type), reg1 = resultRegister, reg2 = 0), null, fcall.position) } } - return code + return result } is StRomSub -> { - val code = IRCodeChunk(fcall.position) + val result = mutableListOf() for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) { val paramDt = codeGen.irType(parameter.type) val paramRegStr = if(parameter.register.registerOrPair!=null) parameter.register.registerOrPair.toString() else parameter.register.statusflag.toString() if(codeGen.isZero(arg)) { - code += IRInstruction(Opcode.STOREZCPU, paramDt, labelSymbol = paramRegStr) + addInstr(result, IRInstruction(Opcode.STOREZCPU, paramDt, labelSymbol = paramRegStr), null, fcall.position) } else { if (paramDt == IRDataType.FLOAT) throw AssemblyError("doesn't support float register argument in asm romsub") val argReg = codeGen.registers.nextFree() - code += translateExpression(arg, argReg, -1) - code += IRInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr) + result += translateExpression(arg, argReg, -1) + addInstr(result, IRInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr), null, fcall.position) } } - code += IRInstruction(Opcode.CALL, value=callTarget.address.toInt()) + addInstr(result, IRInstruction(Opcode.CALL, value=callTarget.address.toInt()), null, fcall.position) if(!fcall.void) { if(callTarget.returns.size!=1) throw AssemblyError("expect precisely 1 return value") @@ -935,12 +974,19 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { throw AssemblyError("doesn't support float register result in asm romsub") val returns = callTarget.returns.single() val regStr = if(returns.registerOrPair!=null) returns.registerOrPair.toString() else returns.statusflag.toString() - code += IRInstruction(Opcode.LOADCPU, codeGen.irType(fcall.type), reg1=resultRegister, labelSymbol = regStr) + addInstr(result, IRInstruction(Opcode.LOADCPU, codeGen.irType(fcall.type), reg1=resultRegister, labelSymbol = regStr), null, fcall.position) } - return code + return result } else -> throw AssemblyError("invalid node type") } } } + + +internal fun addInstr(code: MutableList, instr: IRInstruction, label: String?, position: Position = Position.DUMMY) { + code += IRCodeChunk(label, position).also { + it += instr + } +} diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 417d8c5e4..f8c6e3d36 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -34,9 +34,12 @@ class IRCodeGen( if(!options.dontReinitGlobals) { // collect global variables initializers program.allBlocks().forEach { - val code = IRCodeChunk(it.position) - it.children.filterIsInstance().forEach { assign -> code += assignmentGen.translate(assign) } - irProg.addGlobalInits(code) + val result = mutableListOf() + it.children.filterIsInstance().forEach { assign -> result += assignmentGen.translate(assign) } + result.forEach { chunk -> + if (chunk is IRCodeChunk) irProg.addGlobalInits(chunk) + else throw AssemblyError("only expect code chunk for global inits") + } } } @@ -209,17 +212,17 @@ class IRCodeGen( } } - internal fun translateNode(node: PtNode): IRCodeChunkBase { - val code = when(node) { - is PtScopeVarsDecls -> IRCodeChunk(node.position) // vars should be looked up via symbol table - is PtVariable -> IRCodeChunk(node.position) // var should be looked up via symbol table - is PtMemMapped -> IRCodeChunk(node.position) // memmapped var should be looked up via symbol table - is PtConstant -> IRCodeChunk(node.position) // constants have all been folded into the code + internal fun translateNode(node: PtNode): IRCodeChunks { + return when(node) { + is PtScopeVarsDecls -> emptyList() // vars should be looked up via symbol table + is PtVariable -> emptyList() // var should be looked up via symbol table + is PtMemMapped -> emptyList() // memmapped var should be looked up via symbol table + is PtConstant -> emptyList() // constants have all been folded into the code is PtAssignment -> assignmentGen.translate(node) - is PtNodeGroup -> translateGroup(node.children, node.position) + is PtNodeGroup -> translateGroup(node.children) is PtBuiltinFunctionCall -> translateBuiltinFunc(node, 0) is PtFunctionCall -> expressionEval.translate(node, 0, 0) - is PtNop -> IRCodeChunk(node.position) + is PtNop -> emptyList() is PtReturn -> translate(node) is PtJump -> translate(node) is PtWhen -> translate(node) @@ -227,23 +230,19 @@ class IRCodeGen( is PtIfElse -> translate(node) is PtPostIncrDecr -> translate(node) is PtRepeatLoop -> translate(node) - is PtLabel -> { - val chunk = IRCodeChunk(node.position) - chunk += IRCodeLabel(node.name) - return chunk - } + is PtLabel -> listOf(IRCodeChunk(node.name, node.position)) is PtBreakpoint -> { - val chunk = IRCodeChunk(node.position) + val chunk = IRCodeChunk(null, node.position) chunk += IRInstruction(Opcode.BREAKPOINT) - return chunk + listOf(chunk) } is PtConditionalBranch -> translate(node) - is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.isIR, node.position) + is PtInlineAssembly -> listOf(IRInlineAsmChunk(null, node.assembly, node.isIR, node.position)) is PtIncludeBinary -> { val data = node.file.readBytes() .drop(node.offset?.toInt() ?: 0) .take(node.length?.toInt() ?: Int.MAX_VALUE) - return IRInlineBinaryChunk(data.map { it.toUByte() }, node.position) + listOf(IRInlineBinaryChunk(null, data.map { it.toUByte() }, node.position)) } is PtAddressOf, is PtContainmentCheck, @@ -265,14 +264,13 @@ class IRCodeGen( is PtSub -> throw AssemblyError("nested subroutines should have been flattened ${node.position}") else -> TODO("missing codegen for $node") } - return code } - private fun translate(branch: PtConditionalBranch): IRCodeChunk { - val code = IRCodeChunk(branch.position) + private fun translate(branch: PtConditionalBranch): IRCodeChunks { + val result = mutableListOf() 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) { + val branchIns = when(branch.condition) { BranchCondition.CS -> IRInstruction(Opcode.BSTCC, labelSymbol = elseLabel) BranchCondition.CC -> IRInstruction(Opcode.BSTCS, labelSymbol = elseLabel) BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTNE, labelSymbol = elseLabel) @@ -282,70 +280,97 @@ class IRCodeGen( BranchCondition.VC -> IRInstruction(Opcode.BSTVC, labelSymbol = elseLabel) BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel) } - code += translateNode(branch.trueScope) + addInstr(result, branchIns, null, branch.position) + result += translateNode(branch.trueScope) if(branch.falseScope.children.isNotEmpty()) { val endLabel = createLabelName() - code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel) - code += IRCodeLabel(elseLabel) - code += translateNode(branch.falseScope) - code += IRCodeLabel(endLabel) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null, branch.position) + val chunks = translateNode(branch.falseScope) + result += labelFirstChunk(chunks, elseLabel) + result += IRCodeChunk(endLabel, branch.position) } else { - code += IRCodeLabel(elseLabel) + result += IRCodeChunk(elseLabel, branch.position) } - return code + return result } - private fun translate(whenStmt: PtWhen): IRCodeChunk { - val code = IRCodeChunk(whenStmt.position) + private fun labelFirstChunk(chunks: IRCodeChunks, label: String): IRCodeChunks { + require(chunks.isNotEmpty() && label.isNotBlank()) + val newChunks = chunks.drop(1).toMutableList() + val labeledFirstChunk = when(val first=chunks[0]) { + is IRCodeChunk -> { + val newChunk = IRCodeChunk(label, first.position) + first.instructions.forEach { newChunk += it } + newChunk + } + is IRInlineAsmChunk -> { + IRInlineAsmChunk(label, first.assembly, first.isIR, first.position) + } + is IRInlineBinaryChunk -> { + IRInlineBinaryChunk(label, first.data, first.position) + } + else -> { + throw AssemblyError("invalid chunk") + } + } + newChunks.add(0, labeledFirstChunk) + return newChunks + } + + private fun translate(whenStmt: PtWhen): IRCodeChunks { if(whenStmt.choices.children.isEmpty()) - return code + return emptyList() + val result = mutableListOf() val valueReg = registers.nextFree() val choiceReg = registers.nextFree() val valueDt = irType(whenStmt.value.type) - code += expressionEval.translateExpression(whenStmt.value, valueReg, -1) + result += expressionEval.translateExpression(whenStmt.value, valueReg, -1) val choices = whenStmt.choices.children.map {it as PtWhenChoice } val endLabel = createLabelName() for (choice in choices) { if(choice.isElse) { - code += translateNode(choice.statements) + result += translateNode(choice.statements) } else { val skipLabel = createLabelName() val values = choice.values.children.map {it as PtNumber} if(values.size==1) { - code += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt()) - code += IRInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel) - code += translateNode(choice.statements) + val chunk = IRCodeChunk(null, whenStmt.position) + chunk += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt()) + chunk += IRInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel) + result += chunk + result += translateNode(choice.statements) if(choice.statements.children.last() !is PtReturn) - code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null, whenStmt.position) } else { val matchLabel = createLabelName() + val chunk = IRCodeChunk(null, whenStmt.position) for (value in values) { - code += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt()) - code += IRInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel) + chunk += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt()) + chunk += IRInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel) } - code += IRInstruction(Opcode.JUMP, labelSymbol = skipLabel) - code += IRCodeLabel(matchLabel) - code += translateNode(choice.statements) + chunk += IRInstruction(Opcode.JUMP, labelSymbol = skipLabel) + result += chunk + result += labelFirstChunk(translateNode(choice.statements), matchLabel) if(choice.statements.children.last() !is PtReturn) - code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null, whenStmt.position) } - code += IRCodeLabel(skipLabel) + result += IRCodeChunk(skipLabel, whenStmt.position) } } - code += IRCodeLabel(endLabel) - return code + result += IRCodeChunk(endLabel, whenStmt.position) + return result } - private fun translate(forLoop: PtForLoop): IRCodeChunk { + private fun translate(forLoop: PtForLoop): IRCodeChunks { val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable val iterable = forLoop.iterable - val code = IRCodeChunk(forLoop.position) + val result = mutableListOf() when(iterable) { is PtRange -> { if(iterable.from is PtNumber && iterable.to is PtNumber) - code += translateForInConstantRange(forLoop, loopvar) + result += translateForInConstantRange(forLoop, loopvar) else - code += translateForInNonConstantRange(forLoop, loopvar) + result += translateForInNonConstantRange(forLoop, loopvar) } is PtIdentifier -> { val symbol = iterable.targetName.joinToString(".") @@ -357,15 +382,18 @@ class IRCodeGen( val endLabel = createLabelName() if(iterableVar.dt==DataType.STR) { // iterate over a zero-terminated string - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0) - code += IRCodeLabel(loopLabel) - code += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol) - code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel) - code += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol) - code += translateNode(forLoop.statements) - code += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) - code += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel) - code += IRCodeLabel(endLabel) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0), null, forLoop.position) + val chunk = IRCodeChunk(loopLabel, forLoop.position) + chunk += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol) + chunk += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel) + chunk += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol) + result += chunk + result += translateNode(forLoop.statements) + val jumpChunk = IRCodeChunk(null, forLoop.position) + jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) + jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel) + result += jumpChunk + result += IRCodeChunk(endLabel, forLoop.position) } else { // iterate over array val elementDt = ArrayToElementTypes.getValue(iterable.type) @@ -373,22 +401,26 @@ class IRCodeGen( val lengthBytes = iterableVar.length!! * elementSize if(lengthBytes<256) { val lengthReg = registers.nextFree() - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0) - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, value=lengthBytes) - code += IRCodeLabel(loopLabel) - code += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol) - code += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) - code += translateNode(forLoop.statements) - code += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position) - code += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel) + val chunk = IRCodeChunk(null, forLoop.position) + chunk += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0) + chunk += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, value=lengthBytes) + result += chunk + val chunk2 = IRCodeChunk(loopLabel, forLoop.position) + chunk2 += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol) + chunk2 += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) + result += chunk2 + result += translateNode(forLoop.statements) + result += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position) + addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel), null, forLoop.position) } else if(lengthBytes==256) { - code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0) - code += IRCodeLabel(loopLabel) - code += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol) - code += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) - code += translateNode(forLoop.statements) - code += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position) - code += IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel) + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0), null, forLoop.position) + val chunk = IRCodeChunk(loopLabel, forLoop.position) + chunk += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol) + chunk += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol) + result += chunk + result += translateNode(forLoop.statements) + result += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position) + addInstr(result, IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel), null, forLoop.position) } else { throw AssemblyError("iterator length should never exceed 256") } @@ -396,10 +428,10 @@ class IRCodeGen( } else -> throw AssemblyError("weird for iterable") } - return code + return result } - private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunk { + private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunks { val iterable = forLoop.iterable as PtRange val step = iterable.step.number.toInt() if (step==0) @@ -409,21 +441,20 @@ class IRCodeGen( val loopvarSymbol = loopvar.scopedName.joinToString(".") val loopvarDt = irType(loopvar.dt) val loopLabel = createLabelName() - val code = IRCodeChunk(forLoop.position) + val result = mutableListOf() - code += expressionEval.translateExpression(iterable.to, endvalueReg, -1) - code += expressionEval.translateExpression(iterable.from, indexReg, -1) - code += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol) - code += IRCodeLabel(loopLabel) - code += translateNode(forLoop.statements) - code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position) - code += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol) + result += expressionEval.translateExpression(iterable.to, endvalueReg, -1) + result += expressionEval.translateExpression(iterable.from, indexReg, -1) + addInstr(result, IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol), null, forLoop.position) + result += labelFirstChunk(translateNode(forLoop.statements), loopLabel) + result += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position) + addInstr(result, IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol), null, forLoop.position) val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE - code += IRInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel) - return code + addInstr(result, IRInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel), null, forLoop.position) + return result } - private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunk { + private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunks { val loopLabel = createLabelName() val loopvarSymbol = loopvar.scopedName.joinToString(".") val indexReg = registers.nextFree() @@ -437,30 +468,33 @@ class IRCodeGen( if(step>0 && rangeEndUntypedrangeStart) throw AssemblyError("empty range") val rangeEndWrapped = if(loopvarDt==IRDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535 - val code = IRCodeChunk(forLoop.position) val endvalueReg: Int + val result = mutableListOf() + val chunk = IRCodeChunk(null, forLoop.position) if(rangeEndWrapped!=0) { endvalueReg = registers.nextFree() - code += IRInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped) + chunk += IRInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped) } else { endvalueReg = -1 // not used } - code += IRInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart) - code += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol) - code += IRCodeLabel(loopLabel) - code += translateNode(forLoop.statements) - code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position) - code += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol) - code += if(rangeEndWrapped==0) { + chunk += IRInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart) + chunk += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol) + result += chunk + result += labelFirstChunk(translateNode(forLoop.statements), loopLabel) + result += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position) + val chunk2 = IRCodeChunk(null, forLoop.position) + chunk2 += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol) + chunk2 += if(rangeEndWrapped==0) { IRInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel) } else { IRInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel) } - return code + result += chunk2 + return result } private fun addConstReg(dt: IRDataType, reg: Int, value: Int, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) when(value) { 0 -> { /* do nothing */ } 1 -> { @@ -489,7 +523,7 @@ class IRCodeGen( } private fun addConstMem(dt: IRDataType, knownAddress: UInt?, symbol: String?, value: Int, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) when(value) { 0 -> { /* do nothing */ } 1 -> { @@ -544,7 +578,7 @@ class IRCodeGen( } internal fun multiplyByConstFloat(fpReg: Int, factor: Float, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1f) return code code += if(factor==0f) { @@ -556,7 +590,7 @@ class IRCodeGen( } internal fun multiplyByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Float, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1f) return code if(factor==0f) { @@ -578,7 +612,7 @@ class IRCodeGen( internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() } internal fun multiplyByConst(dt: IRDataType, reg: Int, factor: Int, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -602,7 +636,7 @@ class IRCodeGen( } internal fun multiplyByConstInplace(dt: IRDataType, knownAddress: Int?, symbol: String?, factor: Int, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -641,7 +675,7 @@ class IRCodeGen( } internal fun divideByConstFloat(fpReg: Int, factor: Float, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1f) return code code += if(factor==0f) { @@ -653,7 +687,7 @@ class IRCodeGen( } internal fun divideByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Float, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1f) return code if(factor==0f) { @@ -675,7 +709,7 @@ class IRCodeGen( } internal fun divideByConst(dt: IRDataType, reg: Int, factor: Int, signed: Boolean, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -704,7 +738,7 @@ class IRCodeGen( } internal fun divideByConstInplace(dt: IRDataType, knownAddress: Int?, symbol: String?, factor: Int, signed: Boolean, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) + val code = IRCodeChunk(null, position) if(factor==1) return code val pow2 = powersOfTwo.indexOf(factor) @@ -760,15 +794,15 @@ class IRCodeGen( return code } - private fun translate(ifElse: PtIfElse): IRCodeChunk { + private fun translate(ifElse: PtIfElse): IRCodeChunks { if(ifElse.condition.operator !in ComparisonOperators) throw AssemblyError("if condition should only be a binary comparison expression") val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) val irDt = irType(ifElse.condition.left.type) - val code = IRCodeChunk(ifElse.position) - fun translateNonZeroComparison(): IRCodeChunk { + fun translateNonZeroComparison(): IRCodeChunks { + val result = mutableListOf() val elseBranch = when(ifElse.condition.operator) { "==" -> Opcode.BNE "!=" -> Opcode.BEQ @@ -781,50 +815,49 @@ class IRCodeGen( val leftReg = registers.nextFree() val rightReg = registers.nextFree() - code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1) - code += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1) + result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1) + result += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1) if(ifElse.elseScope.children.isNotEmpty()) { // if and else parts val elseLabel = createLabelName() val afterIfLabel = createLabelName() - code += IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel) - code += translateNode(ifElse.ifScope) - code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel) - code += IRCodeLabel(elseLabel) - code += translateNode(ifElse.elseScope) - code += IRCodeLabel(afterIfLabel) + addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel), null, ifElse.position) + result += translateNode(ifElse.ifScope) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null, ifElse.position) + result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel) + result += IRCodeChunk(afterIfLabel, ifElse.position) } else { // only if part val afterIfLabel = createLabelName() - code += IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel) - code += translateNode(ifElse.ifScope) - code += IRCodeLabel(afterIfLabel) + addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel), null, ifElse.position) + result += translateNode(ifElse.ifScope) + result += IRCodeChunk(afterIfLabel, ifElse.position) } - return code + return result } - fun translateZeroComparison(): IRCodeChunk { - fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunk { + fun translateZeroComparison(): IRCodeChunks { + fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunks { + val result = mutableListOf() val leftReg = registers.nextFree() - code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1) + result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1) if(ifElse.elseScope.children.isNotEmpty()) { // if and else parts val elseLabel = createLabelName() val afterIfLabel = createLabelName() - code += IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = elseLabel) - code += translateNode(ifElse.ifScope) - code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel) - code += IRCodeLabel(elseLabel) - code += translateNode(ifElse.elseScope) - code += IRCodeLabel(afterIfLabel) + addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = elseLabel), null, ifElse.position) + result += translateNode(ifElse.ifScope) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null, ifElse.position) + result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel) + result += IRCodeChunk(afterIfLabel, ifElse.position) } else { // only if part val afterIfLabel = createLabelName() - code += IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = afterIfLabel) - code += translateNode(ifElse.ifScope) - code += IRCodeLabel(afterIfLabel) + addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = afterIfLabel), null, ifElse.position) + result += translateNode(ifElse.ifScope) + result += IRCodeChunk(afterIfLabel, ifElse.position) } - return code + return result } return when (ifElse.condition.operator) { @@ -849,8 +882,7 @@ class IRCodeGen( translateNonZeroComparison() } - private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk { - val code = IRCodeChunk(postIncrDecr.position) + private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks { val operationMem: Opcode val operationRegister: Opcode when(postIncrDecr.operator) { @@ -868,19 +900,22 @@ class IRCodeGen( val memory = postIncrDecr.target.memory val array = postIncrDecr.target.array val irDt = irType(postIncrDecr.target.type) + val result = mutableListOf() if(ident!=null) { - code += IRInstruction(operationMem, irDt, labelSymbol = ident.targetName.joinToString(".")) + addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.targetName.joinToString(".")), null, postIncrDecr.position) } else if(memory!=null) { if(memory.address is PtNumber) { val address = (memory.address as PtNumber).number.toInt() - code += IRInstruction(operationMem, irDt, value = address) + addInstr(result, IRInstruction(operationMem, irDt, value = address), null, postIncrDecr.position) } else { val incReg = registers.nextFree() val addressReg = registers.nextFree() - code += expressionEval.translateExpression(memory.address, addressReg, -1) - code += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = addressReg) - code += IRInstruction(operationRegister, irDt, reg1 = incReg) - code += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = addressReg) + result += expressionEval.translateExpression(memory.address, addressReg, -1) + val chunk = IRCodeChunk(null, postIncrDecr.position) + chunk += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = addressReg) + chunk += IRInstruction(operationRegister, irDt, reg1 = incReg) + chunk += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = addressReg) + result += chunk } } else if (array!=null) { val variable = array.variable.targetName.joinToString(".") @@ -888,25 +923,27 @@ class IRCodeGen( val fixedIndex = constIntValue(array.index) if(fixedIndex!=null) { val offset = fixedIndex*itemsize - code += IRInstruction(operationMem, irDt, labelSymbol="$variable+$offset") + addInstr(result, IRInstruction(operationMem, irDt, labelSymbol="$variable+$offset"), null, postIncrDecr.position) } else { val incReg = registers.nextFree() val indexReg = registers.nextFree() - code += expressionEval.translateExpression(array.index, indexReg, -1) - code += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable) - code += IRInstruction(operationRegister, irDt, reg1=incReg) - code += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable) + result += expressionEval.translateExpression(array.index, indexReg, -1) + val chunk = IRCodeChunk(null, postIncrDecr.position) + chunk += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable) + chunk += IRInstruction(operationRegister, irDt, reg1=incReg) + chunk += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable) + result += chunk } } else throw AssemblyError("weird assigntarget") - return code + return result } - private fun translate(repeat: PtRepeatLoop): IRCodeChunk { + private fun translate(repeat: PtRepeatLoop): IRCodeChunks { when (constIntValue(repeat.count)) { - 0 -> return IRCodeChunk(repeat.position) - 1 -> return translateGroup(repeat.children, repeat.position) + 0 -> return emptyList() + 1 -> return translateGroup(repeat.children) 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) @@ -915,22 +952,23 @@ class IRCodeGen( val repeatLabel = createLabelName() val skipRepeatLabel = createLabelName() - val code = IRCodeChunk(repeat.position) val counterReg = registers.nextFree() val irDt = irType(repeat.count.type) - code += expressionEval.translateExpression(repeat.count, counterReg, -1) - code += IRInstruction(Opcode.BZ, irDt, reg1=counterReg, labelSymbol = skipRepeatLabel) - code += IRCodeLabel(repeatLabel) - code += translateNode(repeat.statements) - code += IRInstruction(Opcode.DEC, irDt, reg1=counterReg) - code += IRInstruction(Opcode.BNZ, irDt, reg1=counterReg, labelSymbol = repeatLabel) - code += IRCodeLabel(skipRepeatLabel) - return code + val result = mutableListOf() + result += expressionEval.translateExpression(repeat.count, counterReg, -1) + addInstr(result, IRInstruction(Opcode.BZ, irDt, reg1=counterReg, labelSymbol = skipRepeatLabel), null, repeat.position) + result += labelFirstChunk(translateNode(repeat.statements), repeatLabel) + val chunk = IRCodeChunk(null, repeat.position) + chunk += IRInstruction(Opcode.DEC, irDt, reg1=counterReg) + chunk += IRInstruction(Opcode.BNZ, irDt, reg1=counterReg, labelSymbol = repeatLabel) + result += chunk + result += IRCodeChunk(skipRepeatLabel, repeat.position) + return result } - private fun translate(jump: PtJump): IRCodeChunk { - val code = IRCodeChunk(jump.position) - code += if(jump.address!=null) { + private fun translate(jump: PtJump): IRCodeChunks { + val result = mutableListOf() + val instr = if(jump.address!=null) { IRInstruction(Opcode.JUMPA, value = jump.address!!.toInt()) } else { if (jump.generatedLabel != null) @@ -940,27 +978,28 @@ class IRCodeGen( else throw AssemblyError("weird jump") } - return code + addInstr(result, instr, null, jump.position) + return result } - private fun translateGroup(group: List, position: Position): IRCodeChunk { - val code = IRCodeChunk(position) - group.forEach { code += translateNode(it) } - return code + private fun translateGroup(group: List): IRCodeChunks { + val result = mutableListOf() + group.forEach { result += translateNode(it) } + return result } - private fun translate(ret: PtReturn): IRCodeChunk { - val code = IRCodeChunk(ret.position) + private fun translate(ret: PtReturn): IRCodeChunks { + val result = mutableListOf() val value = ret.value if(value!=null) { // Call Convention: return value is always returned in r0 (or fr0 if float) - code += if(value.type==DataType.FLOAT) + result += if(value.type==DataType.FLOAT) expressionEval.translateExpression(value, -1, 0) else expressionEval.translateExpression(value, 0, -1) } - code += IRInstruction(Opcode.RETURN) - return code + addInstr(result, IRInstruction(Opcode.RETURN), null, ret.position) + return result } private fun translate(block: PtBlock): IRBlock { @@ -973,9 +1012,7 @@ class IRCodeGen( is PtSub -> { val sub = IRSubroutine(child.name, translate(child.parameters), child.returntype, child.position) for (subchild in child.children) { - val translated = translateNode(subchild) - if(translated.isNotEmpty()) - sub += translated + translateNode(subchild).forEach { sub += it } } irBlock += sub } @@ -991,7 +1028,7 @@ class IRCodeGen( ) } is PtInlineAssembly -> { - irBlock += IRInlineAsmChunk(child.assembly, child.isIR, child.position) + irBlock += IRInlineAsmChunk(null, child.assembly, child.isIR, child.position) } else -> TODO("weird child node $child") } @@ -1034,7 +1071,7 @@ class IRCodeGen( return "prog8_label_gen_$labelSequenceNumber" } - internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk = + internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks = builtinFuncGen.translate(call, resultRegister) internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0 diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index c8ddfc688..ba4133299 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -34,7 +34,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) { TODO: this has to be changed later... */ - if(sub.chunks.isEmpty()) +/* if(sub.chunks.isEmpty()) return fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean { @@ -56,7 +56,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) { chunks += sub.chunks[ix] } sub.chunks.clear() - sub.chunks += chunks + sub.chunks += chunks*/ } private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List>): Boolean { @@ -112,15 +112,16 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) { var changed = false indexedInstructions.reversed().forEach { (idx, ins) -> val labelSymbol = ins.labelSymbol + if(ins.opcode== Opcode.JUMP && labelSymbol!=null) { - // remove jump/branch to label immediately below - if(idx < chunk.instructions.size-1) { - val label = chunk.instructions[idx+1] as? IRCodeLabel - if(label?.name == labelSymbol) { - chunk.instructions.removeAt(idx) - changed = true - } - } + // TODO remove jump/branch to label immediately below (= next chunk if it has that label) +// if(idx < chunk.instructions.size-1) { +// val label = chunk.instructions[idx+1] as? IRCodeLabel +// if(label?.name == labelSymbol) { +// chunk.instructions.removeAt(idx) +// changed = true +// } +// } } // remove useless RETURN if(ins.opcode == Opcode.RETURN && idx>0) { diff --git a/codeGenIntermediate/test/TestIRPeepholeOpt.kt b/codeGenIntermediate/test/TestIRPeepholeOpt.kt index 23c8a9dc1..7b0487ffb 100644 --- a/codeGenIntermediate/test/TestIRPeepholeOpt.kt +++ b/codeGenIntermediate/test/TestIRPeepholeOpt.kt @@ -6,13 +6,10 @@ import prog8.codegen.intermediate.IRPeepholeOptimizer import prog8.intermediate.* class TestIRPeepholeOpt: FunSpec({ - fun makeIRProgram(instructions: List): IRProgram { + fun makeIRProgram(chunks: List): IRProgram { val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY) val sub = IRSubroutine("main.start", emptyList(), null, Position.DUMMY) - val chunk = IRCodeChunk(Position.DUMMY) - for(instr in instructions) - chunk += instr - sub += chunk + chunks.forEach { sub += it } block += sub val target = VMTarget() val options = CompilationOptions( @@ -30,7 +27,13 @@ class TestIRPeepholeOpt: FunSpec({ return prog } - fun IRProgram.instructions(): List = this.blocks.flatMap { it.subroutines }.flatMap { it.chunks }.flatMap { it.instructions } + fun makeIRProgram(instructions: List): IRProgram { + val chunk = IRCodeChunk(null, Position.DUMMY) + instructions.forEach { chunk += it } + return makeIRProgram(listOf(chunk)) + } + + fun IRProgram.chunks(): List = this.blocks.flatMap { it.subroutines }.flatMap { it.chunks } test("remove nops") { val irProg = makeIRProgram(listOf( @@ -38,33 +41,35 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.NOP), IRInstruction(Opcode.NOP) )) - irProg.instructions().size shouldBe 3 + irProg.chunks().single().instructions.size shouldBe 3 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - irProg.instructions().size shouldBe 1 + irProg.chunks().single().instructions.size shouldBe 1 } test("remove jmp to label below") { - val irProg = makeIRProgram(listOf( - IRInstruction(Opcode.JUMP, labelSymbol = "label"), // removed - IRCodeLabel("label"), - IRInstruction(Opcode.JUMP, labelSymbol = "label2"), // removed - IRInstruction(Opcode.NOP), // removed - IRCodeLabel("label2"), - IRInstruction(Opcode.JUMP, labelSymbol = "label3"), - IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1), - IRCodeLabel("label3") - )) - irProg.instructions().size shouldBe 8 + val c1 = IRCodeChunk(null, Position.DUMMY) + c1 += IRInstruction(Opcode.JUMP, labelSymbol = "label") // removed + val c2 = IRCodeChunk("label", Position.DUMMY) + c2 += IRInstruction(Opcode.JUMP, labelSymbol = "label2") // removed + c2 += IRInstruction(Opcode.NOP) // removed + val c3 = IRCodeChunk("label2", Position.DUMMY) + c3 += IRInstruction(Opcode.JUMP, labelSymbol = "label3") + c3 += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1) + val c4 = IRCodeChunk("label3", Position.DUMMY) + val irProg = makeIRProgram(listOf(c1, c2, c3, c4)) + + irProg.chunks().size shouldBe 4 + irProg.chunks().flatMap { it.instructions }.size shouldBe 5 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - val lines = irProg.instructions() - lines.size shouldBe 5 - (lines[0] as IRCodeLabel).name shouldBe "label" - (lines[1] as IRCodeLabel).name shouldBe "label2" - (lines[2] as IRInstruction).opcode shouldBe Opcode.JUMP - (lines[3] as IRInstruction).opcode shouldBe Opcode.INC - (lines[4] as IRCodeLabel).name shouldBe "label3" + irProg.chunks().size shouldBe 2 + irProg.chunks()[0].label shouldBe "label2" + irProg.chunks()[1].label shouldBe "label3" + val instr = irProg.chunks().flatMap { it.instructions } + instr.size shouldBe 2 + instr[0].opcode shouldBe Opcode.JUMP + instr[1].opcode shouldBe Opcode.INC } test("remove double sec/clc") { @@ -76,12 +81,12 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.CLC), IRInstruction(Opcode.CLC) )) - irProg.instructions().size shouldBe 6 + irProg.chunks().single().instructions.size shouldBe 6 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - val lines = irProg.instructions() - lines.size shouldBe 1 - (lines[0] as IRInstruction).opcode shouldBe Opcode.CLC + val instr = irProg.chunks().single().instructions + instr.size shouldBe 1 + instr[0].opcode shouldBe Opcode.CLC } test("push followed by pop") { @@ -91,14 +96,14 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=99), IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=222) )) - irProg.instructions().size shouldBe 4 + irProg.chunks().single().instructions.size shouldBe 4 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - val lines = irProg.instructions() - lines.size shouldBe 1 - (lines[0] as IRInstruction).opcode shouldBe Opcode.LOADR - (lines[0] as IRInstruction).reg1 shouldBe 222 - (lines[0] as IRInstruction).reg2 shouldBe 99 + val instr = irProg.chunks().single().instructions + instr.size shouldBe 1 + instr[0].opcode shouldBe Opcode.LOADR + instr[0].reg1 shouldBe 222 + instr[0].reg2 shouldBe 99 } test("remove useless div/mul, add/sub") { @@ -114,11 +119,10 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 0), IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 0) )) - irProg.instructions().size shouldBe 10 + irProg.chunks().single().instructions.size shouldBe 10 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - val lines = irProg.instructions() - lines.size shouldBe 4 + irProg.chunks().single().instructions.size shouldBe 4 } test("replace add/sub 1 by inc/dec") { @@ -126,13 +130,13 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 1), IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 1) )) - irProg.instructions().size shouldBe 2 + irProg.chunks().single().instructions.size shouldBe 2 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - val lines = irProg.instructions() - lines.size shouldBe 2 - (lines[0] as IRInstruction).opcode shouldBe Opcode.INC - (lines[1] as IRInstruction).opcode shouldBe Opcode.DEC + val instr = irProg.chunks().single().instructions + instr.size shouldBe 2 + instr[0].opcode shouldBe Opcode.INC + instr[1].opcode shouldBe Opcode.DEC } test("remove useless and/or/xor") { @@ -146,11 +150,10 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 1), IRInstruction(Opcode.XOR, IRDataType.BYTE, reg1=42, value = 1) )) - irProg.instructions().size shouldBe 8 + irProg.chunks().single().instructions.size shouldBe 8 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - val lines = irProg.instructions() - lines.size shouldBe 4 + irProg.chunks().single().instructions.size shouldBe 4 } test("replace and/or/xor by constant number") { @@ -160,18 +163,18 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 255), IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, value = 65535) )) - irProg.instructions().size shouldBe 4 + irProg.chunks().single().instructions.size shouldBe 4 val opt = IRPeepholeOptimizer(irProg) opt.optimize() - val lines = irProg.instructions() - lines.size shouldBe 4 - (lines[0] as IRInstruction).opcode shouldBe Opcode.LOAD - (lines[1] as IRInstruction).opcode shouldBe Opcode.LOAD - (lines[2] as IRInstruction).opcode shouldBe Opcode.LOAD - (lines[3] as IRInstruction).opcode shouldBe Opcode.LOAD - (lines[0] as IRInstruction).value shouldBe 0 - (lines[1] as IRInstruction).value shouldBe 0 - (lines[2] as IRInstruction).value shouldBe 255 - (lines[3] as IRInstruction).value shouldBe 65535 + val instr = irProg.chunks().single().instructions + instr.size shouldBe 4 + instr[0].opcode shouldBe Opcode.LOAD + instr[1].opcode shouldBe Opcode.LOAD + instr[2].opcode shouldBe Opcode.LOAD + instr[3].opcode shouldBe Opcode.LOAD + instr[0].value shouldBe 0 + instr[1].value shouldBe 0 + instr[2].value shouldBe 255 + instr[3].value shouldBe 65535 } }) \ No newline at end of file diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 3e20573fb..ab230fb81 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,7 +4,10 @@ TODO For next release ^^^^^^^^^^^^^^^^ - ir: get rid of IRCodeLabel, make every label start a new code chunk, give those a 'label' property. -- ir: fix joinChunks() in the IR optimizer ? +- ir: fix program to be list of chunks +- ir: jump/branch instructions don't link to a PC index anymore, but to the actual chunk with that label +- ir: fix joinChunks() in the IR optimizer ? Fix TestIRPeepholeOptimizer and TestVm +- vm: program is list of chunks, fix dispatcher ... diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index df2f79efd..7753b4f91 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -32,7 +32,7 @@ class IRFileReader { val memorymapped = parseMemMapped(lines) val slabs = parseSlabs(lines) val initGlobals = parseInitGlobals(lines) - val blocks = parseBlocksUntilProgramEnd(lines, variables) + val blocks = parseBlocksUntilProgramEnd(lines) val st = IRSymbolTable(null) asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)} @@ -261,9 +261,9 @@ class IRFileReader { if(line!="") throw IRParseException("invalid INITGLOBALS") line = lines.next() - var chunk = IRCodeChunk(Position.DUMMY) + var chunk = IRCodeChunk(null, Position.DUMMY) if(line=="") { - chunk = parseCodeChunk(line, lines)!! + chunk = parseCodeChunk(line, lines, null)!! line = lines.next() } if(line!="") @@ -271,7 +271,7 @@ class IRFileReader { return chunk } - private fun parseBlocksUntilProgramEnd(lines: Iterator, variables: List): List { + private fun parseBlocksUntilProgramEnd(lines: Iterator): List { val blocks = mutableListOf() while(true) { var line = lines.next() @@ -279,7 +279,7 @@ class IRFileReader { line = lines.next() if (line == "") break - blocks.add(parseBlock(line, lines, variables)) + blocks.add(parseBlock(line, lines)) } return blocks } @@ -291,7 +291,7 @@ class IRFileReader { private val subPattern = Regex("") private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]") - private fun parseBlock(startline: String, lines: Iterator, variables: List): IRBlock { + private fun parseBlock(startline: String, lines: Iterator): IRBlock { var line = startline if(!line.startsWith("") return block if(line.startsWith("): IRInlineAsmChunk { + private fun parseInlineAssembly(startline: String, lines: Iterator, label: String?): IRInlineAsmChunk { // val match = inlineAsmPattern.matchEntire(startline) ?: throw IRParseException("invalid INLINEASM") val isIr = match.groupValues[1].toBoolean() @@ -330,7 +330,7 @@ class IRFileReader { asmlines.add(line) line = lines.next() } - return IRInlineAsmChunk(asmlines.joinToString("\n"), isIr, pos) + return IRInlineAsmChunk(label, asmlines.joinToString("\n"), isIr, pos) } private fun parseAsmSubroutine(startline: String, lines: Iterator): IRAsmSubroutine { @@ -352,7 +352,7 @@ class IRFileReader { params += Pair(dt, regsf) } line = lines.next() - val asm = parseInlineAssembly(line, lines) + val asm = parseInlineAssembly(line, lines, null) while(line!="") line = lines.next() val clobberRegs = if(clobbers.isBlank()) emptyList() else clobbers.split(',').map { CpuRegister.valueOf(it) } @@ -374,12 +374,12 @@ class IRFileReader { ) } - private fun parseSubroutine(startline: String, lines: Iterator, variables: List): IRSubroutine { + private fun parseSubroutine(startline: String, lines: Iterator): IRSubroutine { // val match = subPattern.matchEntire(startline) ?: throw IRParseException("invalid SUB") val (name, returntype, pos) = match.destructured val sub = IRSubroutine(name, - parseParameters(lines, variables), + parseParameters(lines), if(returntype=="null") null else parseDatatype(returntype, false), parsePosition(pos)) while(true) { @@ -387,11 +387,11 @@ class IRFileReader { if(line=="") return sub val chunk = if(line=="") - parseCodeChunk(line, lines) + parseCodeChunk(line, lines, null) else if(line.startsWith("): IRInlineBinaryChunk { + private fun parseBinaryBytes(startline: String, lines: Iterator, label: String?): IRInlineBinaryChunk { val match = bytesPattern.matchEntire(startline) ?: throw IRParseException("invalid BYTES") val pos = parsePosition(match.groupValues[1]) val bytes = mutableListOf() @@ -417,10 +417,10 @@ class IRFileReader { } line = lines.next() } - return IRInlineBinaryChunk(bytes, pos) + return IRInlineBinaryChunk(label, bytes, pos) } - private fun parseParameters(lines: Iterator, variables: List): List { + private fun parseParameters(lines: Iterator): List { var line = lines.next() if(line!="") throw IRParseException("missing PARAMS") @@ -436,21 +436,29 @@ class IRFileReader { } } - private fun parseCodeChunk(firstline: String, lines: Iterator): IRCodeChunk? { + private fun parseCodeChunk(firstline: String, lines: Iterator, label: String?): IRCodeChunk? { if(firstline!="") { if(firstline=="") return null else throw IRParseException("invalid or empty ODE chunk") } - val chunk = IRCodeChunk(Position.DUMMY) + val chunk = IRCodeChunk(label, Position.DUMMY) while(true) { val line = lines.next() if (line == "") return chunk if (line.isBlank() || line.startsWith(';')) continue - chunk += parseIRCodeLine(line, 0, mutableMapOf()) + val result = parseIRCodeLine(line, 0, mutableMapOf()) + result.fold( + ifLeft = { + chunk += it + }, + ifRight = { + TODO("PROCESS LABEL $it") + } + ) } } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index 12b2e298a..6ea90028e 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -1,7 +1,9 @@ package prog8.intermediate -import prog8.code.core.* -import java.io.BufferedWriter +import prog8.code.core.ArrayDatatypes +import prog8.code.core.DataType +import prog8.code.core.InternalCompilerException +import prog8.code.core.NumericDatatypes import java.nio.file.Path import kotlin.io.path.bufferedWriter import kotlin.io.path.div @@ -25,7 +27,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { if(!irProgram.options.dontReinitGlobals) { out.write("\n") // note: this a block of code that loads values and stores them into the global variables to reset their values. - irProgram.globalInits.forEach { out.writeLine(it) } + irProgram.globalInits.forEach { out.write(it.toString()) } out.write("\n") } out.write("\n") @@ -67,7 +69,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}") chunk.instructions.forEach { instr -> numInstr++ - out.writeLine(instr) + out.write(instr.toString()) } out.write("\n") } @@ -179,12 +181,4 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { irProgram.st.allMemorySlabs().forEach{ slab -> out.write("SLAB ${slab.name} ${slab.size} ${slab.align}\n") } out.write("\n") } - - private fun BufferedWriter.writeLine(line: IRCodeLine) { - when(line) { - is IRInstruction -> write(line.toString() + "\n") - is IRCodeLabel -> write("_${line.name}:\n") - else -> throw AssemblyError("invalid vm code line") - } - } } \ No newline at end of file diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index 540d3ba88..4951e98bd 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -669,7 +669,7 @@ data class IRInstruction( val fpValue: Float?=null, val labelSymbol: String?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!) val binaryData: Collection?=null -): IRCodeLine() { +) { // reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT) // This knowledge is useful in IL assembly optimizers to see how registers are used. val reg1direction: OperandDirection diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index 2194ce533..365a69896 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -52,7 +52,7 @@ class IRProgram(val name: String, val encoding: IStringEncoding) { val asmSymbols = mutableMapOf() - val globalInits = mutableListOf() + val globalInits = mutableListOf() val blocks = mutableListOf() fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.instructions) @@ -91,10 +91,7 @@ class IRProgram(val name: String, usedRegisters.outputFpRegs.forEach{ (reg, count) -> outputFpRegs[reg] = outputFpRegs.getValue(reg) + count } } - globalInits.forEach { - if(it is IRInstruction) - it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) - } + globalInits.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) } blocks.forEach { it.inlineAssembly.forEach { chunk -> addUsed(chunk.usedRegisters()) } it.subroutines.flatMap { sub->sub.chunks }.forEach { chunk -> addUsed(chunk.usedRegisters()) } @@ -171,19 +168,15 @@ class IRAsmSubroutine( fun usedRegisters() = registersUsed } -sealed class IRCodeLine - -class IRCodeLabel(val name: String): IRCodeLine() - -abstract class IRCodeChunkBase(val position: Position) { - val instructions = mutableListOf() +abstract class IRCodeChunkBase(val label: String?, val position: Position) { + val instructions = mutableListOf() abstract fun isEmpty(): Boolean abstract fun isNotEmpty(): Boolean abstract fun usedRegisters(): RegistersUsed } -class IRCodeChunk(position: Position): IRCodeChunkBase(position) { +class IRCodeChunk(label: String?, position: Position): IRCodeChunkBase(label, position) { override fun isEmpty() = instructions.isEmpty() override fun isNotEmpty() = instructions.isNotEmpty() @@ -192,15 +185,12 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) { val inputFpRegs = mutableMapOf().withDefault { 0 } val outputRegs = mutableMapOf().withDefault { 0 } val outputFpRegs = mutableMapOf().withDefault { 0 } - instructions.forEach { - if(it is IRInstruction) - it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) - } + instructions.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) } return RegistersUsed(inputRegs, outputRegs, inputFpRegs, outputFpRegs) } - operator fun plusAssign(line: IRCodeLine) { - instructions.add(line) + operator fun plusAssign(ins: IRInstruction) { + instructions.add(ins) } operator fun plusAssign(chunk: IRCodeChunkBase) { @@ -208,8 +198,8 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) { } } -class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(position) { - // note: no lines, asm is in the property +class IRInlineAsmChunk(label: String?, val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(label, position) { + // note: no instructions, asm is in the property override fun isEmpty() = assembly.isBlank() override fun isNotEmpty() = assembly.isNotBlank() private val registersUsed by lazy { registersUsedInAssembly(isIR, assembly) } @@ -222,12 +212,15 @@ class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Positi override fun usedRegisters() = registersUsed } -class IRInlineBinaryChunk(val data: Collection, position: Position): IRCodeChunkBase(position) { +class IRInlineBinaryChunk(label: String?, val data: Collection, position: Position): IRCodeChunkBase(label, position) { + // note: no instructions, data is in the property override fun isEmpty() = data.isEmpty() override fun isNotEmpty() = data.isNotEmpty() override fun usedRegisters() = RegistersUsed(emptyMap(), emptyMap(), emptyMap(), emptyMap()) } +typealias IRCodeChunks = List + class RegistersUsed( // register num -> number of uses val inputRegs: Map, @@ -251,9 +244,11 @@ private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersU if(isIR) { assembly.lineSequence().forEach { line -> - val code = parseIRCodeLine(line.trim(), 0, mutableMapOf()) - if(code is IRInstruction) - code.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) + val result = parseIRCodeLine(line.trim(), 0, mutableMapOf()) + result.fold( + ifLeft = { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) }, + ifRight = { /* labels can be skipped */ } + ) } } diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index fd4e63a03..17dfeca25 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -1,7 +1,6 @@ package prog8.intermediate -import prog8.code.StMemVar -import prog8.code.StStaticVariable +import prog8.code.* import prog8.code.core.DataType import prog8.code.core.InternalCompilerException @@ -85,12 +84,12 @@ fun parseIRValue(value: String): Float { private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE) private val labelPattern = Regex("""_([a-zA-Z\d\._]+):""") -fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap): IRCodeLine { +fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap): Either { // Note: this function is used from multiple places: // the IR File Reader but also the VirtualMachine itself to make sense of any inline vmasm blocks. val labelmatch = labelPattern.matchEntire(line.trim()) if(labelmatch!=null) - return IRCodeLabel(labelmatch.groupValues[1]) + return right(labelmatch.groupValues[1]) // it's a label. val match = instructionPattern.matchEntire(line) ?: throw IRParseException("invalid IR instruction: $line") @@ -240,8 +239,8 @@ fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap "pc", "pz", "pv","pn")) throw IRParseException("invalid cpu reg: $reg") - return IRInstruction(opcode, type, reg1, labelSymbol = reg) + return left(IRInstruction(opcode, type, reg1, labelSymbol = reg)) } - return IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue, labelSymbol = labelSymbol) + return left(IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue, labelSymbol = labelSymbol)) } diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 1ca62bc12..a39deb255 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -44,10 +44,14 @@ class VirtualMachine(irProgram: IRProgram) { private val cx16virtualregsBaseAddress: Int init { + program = emptyArray() // TODO + cx16virtualregsBaseAddress = 0 // TODO +/* TODO !!! program = VmProgramLoader().load(irProgram, memory).toTypedArray() require(program.size<=65536) {"program cannot contain more than 65536 instructions"} require(irProgram.st.getAsmSymbols().isEmpty()) { "virtual machine can't yet process asmsymbols defined on command line" } cx16virtualregsBaseAddress = (irProgram.st.lookup("cx16.r0") as? StMemVar)?.address?.toInt() ?: 0xff02 +*/ } fun run() { diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 6771b4afc..0cdbb750f 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -3,6 +3,7 @@ package prog8.vm import prog8.code.core.DataType import prog8.intermediate.* +/* class VmProgramLoader { private val placeholders = mutableMapOf() // program index to symbolname @@ -13,12 +14,12 @@ class VmProgramLoader { placeholders.clear() val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget) val symbolAddresses = allocations.allocations.toMutableMap() - val program = mutableListOf() + val programChunks = mutableListOf() varsToMemory(irProgram, allocations, symbolAddresses, memory) if(!irProgram.options.dontReinitGlobals) - addToProgram(irProgram.globalInits, program, symbolAddresses) + addToProgram(irProgram.globalInits, programChunks, symbolAddresses) // make sure that if there is a "main.start" entrypoint, we jump to it irProgram.blocks.firstOrNull()?.let { @@ -187,8 +188,8 @@ class VmProgramLoader { } private fun addToProgram( - instructions: Iterable, - program: MutableList, + chunks: Iterable, + program: MutableList, symbolAddresses: MutableMap ) { instructions.map { @@ -241,3 +242,4 @@ class VmProgramLoader { } } } +*/ diff --git a/virtualmachine/test/TestVm.kt b/virtualmachine/test/TestVm.kt index fdbb69ff2..ee5f0bc1f 100644 --- a/virtualmachine/test/TestVm.kt +++ b/virtualmachine/test/TestVm.kt @@ -42,7 +42,7 @@ class TestVm: FunSpec( { val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget()) val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY) val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY) - val code = IRCodeChunk(Position.DUMMY) + val code = IRCodeChunk(null, Position.DUMMY) code += IRInstruction(Opcode.NOP) code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=1, value=12345) code += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1=1, value=1000) @@ -69,7 +69,7 @@ class TestVm: FunSpec( { val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget()) val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY) val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY) - val code = IRCodeChunk(Position.DUMMY) + val code = IRCodeChunk(null, Position.DUMMY) code += IRInstruction(Opcode.BINARYDATA, binaryData = listOf(1u,2u,3u)) code += IRInstruction(Opcode.RETURN) startSub += code