diff --git a/codeAst/src/prog8/code/ast/AstExpressions.kt b/codeAst/src/prog8/code/ast/AstExpressions.kt index a6647bb0c..9685d45ae 100644 --- a/codeAst/src/prog8/code/ast/AstExpressions.kt +++ b/codeAst/src/prog8/code/ast/AstExpressions.kt @@ -188,5 +188,13 @@ class PtTypeCast(type: DataType, position: Position) : PtExpression(type, positi } +// special node that isn't created from compiling user code, but used internally +class PtMachineRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position) { + override fun printProperties() { + print("reg=$register $type") + } +} + + fun constValue(expr: PtExpression): Double? = if(expr is PtNumber) expr.number else null fun constIntValue(expr: PtExpression): Int? = if(expr is PtNumber) expr.number.toInt() else null diff --git a/codeAst/src/prog8/code/ast/AstStatements.kt b/codeAst/src/prog8/code/ast/AstStatements.kt index 34a1f0510..97ca4d061 100644 --- a/codeAst/src/prog8/code/ast/AstStatements.kt +++ b/codeAst/src/prog8/code/ast/AstStatements.kt @@ -62,7 +62,7 @@ class PtAssignTarget(position: Position) : PtNode(position) { is PtIdentifier -> tgt.type is PtArrayIndexer -> tgt.type // TODO array to elt type? is PtMemoryByte -> tgt.type - else -> throw AssemblyError("weird dt") + else -> throw AssemblyError("weird target $tgt") } } diff --git a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt index 4dc3d58de..3d99b760f 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt @@ -29,6 +29,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: "cos8u" -> funcCos8u(call, resultRegister) "sort" -> funcSort(call) "reverse" -> funcReverse(call) + "swap" -> funcSwap(call) "rol" -> funcRolRor2(Opcode.ROXL, call, resultRegister) "ror" -> funcRolRor2(Opcode.ROXR, call, resultRegister) "rol2" -> funcRolRor2(Opcode.ROL, call, resultRegister) @@ -57,6 +58,19 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } } + private fun funcSwap(call: PtBuiltinFunctionCall): VmCodeChunk { + val left = call.args[0] + val right = call.args[1] + val leftReg = codeGen.vmRegisters.nextFree() + val rightReg = codeGen.vmRegisters.nextFree() + val code = VmCodeChunk() + code += exprGen.translateExpression(left, leftReg) + code += exprGen.translateExpression(right, rightReg) + code += assignRegisterTo(left, rightReg) + code += assignRegisterTo(right, leftReg) + return code + } + private fun funcReverse(call: PtBuiltinFunctionCall): VmCodeChunk { val arrayName = call.args[0] as PtIdentifier val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable @@ -128,7 +142,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: val code = VmCodeChunk() code += exprGen.translateExpression(call.args[0], addressReg) code += exprGen.translateExpression(call.args[1], valueReg) - code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = addressReg, reg2=valueReg) + // TODO use STOREM if constant address + code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2=addressReg) return code } @@ -138,7 +153,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: val code = VmCodeChunk() code += exprGen.translateExpression(call.args[0], addressReg) code += exprGen.translateExpression(call.args[1], valueReg) - code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = addressReg, reg2=valueReg) + // TODO use STOREM if constant address + code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2=addressReg) return code } @@ -146,6 +162,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: val addressReg = codeGen.vmRegisters.nextFree() val code = VmCodeChunk() code += exprGen.translateExpression(call.args.single(), addressReg) + // TODO use LOADM if constant address code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg) return code } @@ -154,6 +171,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: val code = VmCodeChunk() val addressReg = codeGen.vmRegisters.nextFree() code += exprGen.translateExpression(call.args.single(), addressReg) + // TODO use LOADM if constant address code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg) return code } @@ -252,11 +270,17 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: val code = VmCodeChunk() code += exprGen.translateExpression(call.args[0], resultRegister) code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister) - val assignment = PtAssignment(call.position) - val target = PtAssignTarget(call.position) - target.children.add(call.args[0]) - assignment.children.add(target) - assignment.children.add(PtIdentifier(listOf(":vmreg-$resultRegister"), listOf(":vmreg-$resultRegister"), call.args[0].type, call.position)) + code += assignRegisterTo(call.args[0], resultRegister) + return code + } + + private fun assignRegisterTo(target: PtExpression, register: Int): VmCodeChunk { + val code = VmCodeChunk() + 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 } diff --git a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt index 5d9071830..3a9eb38cd 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt @@ -96,7 +96,7 @@ class CodeGen(internal val program: PtProgram, is PtSubroutineParameter, is PtNumber, is PtArray, - is PtString -> throw AssemblyError("strings should not occur as separate statement node ${node.position}") + is PtString -> throw AssemblyError("should not occur as separate statement node ${node.position}") is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target ${node.position}") is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target ${node.position}") is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target ${node.position}") @@ -461,6 +461,7 @@ class CodeGen(internal val program: PtProgram, } else if(memory!=null) { val addressReg = vmRegisters.nextFree() code += expressionEval.translateExpression(memory.address, addressReg) + // TODO use LOADM/STOREM if address is constant code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg) code += VmCodeInstruction(operation, vmDt, reg1=resultReg) code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg) @@ -533,10 +534,16 @@ class CodeGen(internal val program: PtProgram, private fun translate(assignment: PtAssignment): VmCodeChunk { // TODO can in-place assignments be optimized more? - + if(assignment.target.children.single() is PtMachineRegister) + throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister") val code = VmCodeChunk() - val resultRegister = vmRegisters.nextFree() - code += expressionEval.translateExpression(assignment.value, resultRegister) + val resultRegister = if(assignment.value is PtMachineRegister) { + (assignment.value as PtMachineRegister).register + } else { + val reg = vmRegisters.nextFree() + code += expressionEval.translateExpression(assignment.value, reg) + reg + } val ident = assignment.target.identifier val memory = assignment.target.memory val array = assignment.target.array @@ -561,12 +568,13 @@ class CodeGen(internal val program: PtProgram, } } else if(memory!=null) { + require(vmDt==VmDataType.BYTE) if(memory.address is PtNumber) { code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt()) } else { - val addressRegister = vmRegisters.nextFree() - code += expressionEval.translateExpression(assignment.value, addressRegister) - code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister) + val addressReg = vmRegisters.nextFree() + code += expressionEval.translateExpression(assignment.value, addressReg) + code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg) } } else diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index 30e4e025e..cdc8ba16e 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -18,24 +18,24 @@ internal class ExpressionGen(private val codeGen: CodeGen) { val code = VmCodeChunk() when (expr) { + is PtMachineRegister -> { + if(resultRegister!=expr.register) { + val vmDt = codeGen.vmType(expr.type) + code += VmCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register) + } + } is PtNumber -> { val vmDt = codeGen.vmType(expr.type) code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt()) } is PtIdentifier -> { val vmDt = codeGen.vmType(expr.type) - if(expr.targetName[0].startsWith(":vmreg-")) { - // special direct reference to a register in the VM - val reg = expr.targetName[0].substring(7).toInt() - code += VmCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=reg) + val mem = codeGen.allocations.get(expr.targetName) + code += if (expr.type in PassByValueDatatypes) { + VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem) } else { - val mem = codeGen.allocations.get(expr.targetName) - code += if (expr.type in PassByValueDatatypes) { - VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem) - } else { - // for strings and arrays etc., load the *address* of the value instead - VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem) - } + // for strings and arrays etc., load the *address* of the value instead + VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem) } } is PtAddressOf -> { @@ -45,8 +45,9 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } is PtMemoryByte -> { val addressRegister = codeGen.vmRegisters.nextFree() - val addressExprCode = translateExpression(expr.address, addressRegister) - code += addressExprCode + code += translateExpression(expr.address, addressRegister) + // TODO use LOADM if adress is constant + code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister) } is PtTypeCast -> code += translate(expr, resultRegister) is PtPrefix -> code += translate(expr, resultRegister) @@ -73,12 +74,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return when (segment) { is PtFunctionCall -> { val segWithArg = PtFunctionCall(segment.functionName, segment.void, segment.type, segment.position) - segWithArg.children.add(0, PtIdentifier(listOf(":vmreg-$sourceReg"), listOf(":vmreg-$sourceReg"), sourceDt, segment.position)) + segWithArg.children.add(0, PtMachineRegister(sourceReg, sourceDt, segment.position)) segWithArg } is PtBuiltinFunctionCall -> { val segWithArg = PtBuiltinFunctionCall(segment.name, segment.void, segment.hasNoSideEffects, segment.type, segment.position) - segWithArg.children.add(0, PtIdentifier(listOf(":vmreg-$sourceReg"), listOf(":vmreg-$sourceReg"), sourceDt, segment.position)) + segWithArg.children.add(0, PtMachineRegister(sourceReg, sourceDt, segment.position)) segWithArg } else -> throw AssemblyError("weird segment type") diff --git a/examples/test.p8 b/examples/test.p8 index 34f07a368..c3e7e3f41 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,6 +7,7 @@ main { sub start() { + uword other = $fe4a uword value = $ea31 uword[] warray = [$aa44, $bb55, $cc66] ubyte upperb = msb(value) @@ -28,6 +29,23 @@ main { txt.print_ubhex(upperb, true) txt.print_ubhex(lowerb, false) txt.nl() + swap(other, value) + txt.print_uwhex(value,true) + txt.nl() + txt.nl() + + pokew($1000, $ab98) + txt.print_ubhex(@($1000),true) + txt.print_ubhex(@($1001),false) + txt.nl() + txt.print_uwhex(peekw($1000),true) + txt.nl() + swap(@($1000), @($1001)) + txt.print_uwhex(peekw($1000),true) + txt.nl() + swap(warray[0], warray[1]) + txt.print_uwhex(warray[1],true) + txt.nl() ; ; a "pixelshader": ; void syscall1(8, 0) ; enable lo res creen diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index 657c82532..b1af32a2f 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -39,7 +39,7 @@ storem reg1, address - store reg1 in memory address storei reg1, reg2 - store reg1 in memory indirect, memory pointed to by reg2 storex reg1, reg2, address - store reg1 in memory address, indexed by value in reg2 storez address - store zero in memory address -storezi reg1 - store zero in memory pointed to by reg +storezi reg1 - store zero in memory pointed to by reg1 storezx reg1, address - store zero in memory address, indexed by value in reg