From 199adbbcf015ba93da843c669b23ab5bb54bc846 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 14 Mar 2023 00:45:41 +0100 Subject: [PATCH] IR: don't allow to have 2 same registers on instructions --- .../codegen/intermediate/BuiltinFuncGen.kt | 25 +++++++++++-------- .../codegen/intermediate/ExpressionGen.kt | 17 +++++++------ compiler/src/prog8/compiler/Compiler.kt | 10 +++----- docs/source/todo.rst | 2 -- .../src/prog8/intermediate/IRInstructions.kt | 2 ++ 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index d15ee83ac..775c0eb7d 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -158,20 +158,22 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val vmDt = codeGen.irType(call.type) val tr = exprGen.translateExpression(call.args.single()) addToResult(result, tr, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.SGN, vmDt, reg1 = tr.resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.SGN, vmDt, reg1 = resultReg, reg2 = tr.resultReg) } - return ExpressionCodeResult(result, vmDt, tr.resultReg, -1) + return ExpressionCodeResult(result, vmDt, resultReg, -1) } private fun funcSqrt16(call: PtBuiltinFunctionCall): ExpressionCodeResult { val result = mutableListOf() val tr = exprGen.translateExpression(call.args.single()) addToResult(result, tr, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.SQRT, IRDataType.WORD, reg1=tr.resultReg, reg2=tr.resultReg) + it += IRInstruction(Opcode.SQRT, IRDataType.WORD, reg1=resultReg, reg2=tr.resultReg) } - return ExpressionCodeResult(result, IRDataType.WORD, tr.resultReg, -1) + return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1) } private fun funcPop(call: PtBuiltinFunctionCall): ExpressionCodeResult { @@ -354,10 +356,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } else { val tr = exprGen.translateExpression(call.args.single()) addToResult(result, tr, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = tr.resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = resultReg, reg2 = tr.resultReg) } - ExpressionCodeResult(result, IRDataType.WORD, tr.resultReg, -1) + ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1) } } @@ -373,10 +376,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe } else { val tr = exprGen.translateExpression(call.args.single()) addToResult(result, tr, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = tr.resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultReg, reg2 = tr.resultReg) } - ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) + ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } } @@ -397,11 +401,12 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val result = mutableListOf() val tr = exprGen.translateExpression(call.args.single()) addToResult(result, tr, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = tr.resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultReg, reg2 = tr.resultReg) } // note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here. - return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) + return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall): ExpressionCodeResult { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 9ebd8c31e..cfba5e091 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -84,8 +84,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } else { val tr = translateExpression(expr.address) addToResult(result, tr, tr.resultReg, -1) - addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1=tr.resultReg, reg2=tr.resultReg), null) - ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() + addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1=resultReg, reg2=tr.resultReg), null) + ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } } is PtTypeCast -> translate(expr) @@ -162,8 +163,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { throw AssemblyError("non-array var indexing requires bytes index") val tr = translateExpression(arrayIx.index) addToResult(result, tr, tr.resultReg, -1) - addInstr(result, IRInstruction(Opcode.LOADIX, vmDt, reg1=tr.resultReg, reg2=tr.resultReg, labelSymbol = arrayVarSymbol), null) - return ExpressionCodeResult(result, vmDt, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() + addInstr(result, IRInstruction(Opcode.LOADIX, vmDt, reg1=resultReg, reg2=tr.resultReg, labelSymbol = arrayVarSymbol), null) + return ExpressionCodeResult(result, vmDt, resultReg, -1) } var resultRegister = -1 @@ -188,7 +190,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, IRInstruction(Opcode.LOADX, IRDataType.FLOAT, fpReg1 = resultFpRegister, reg1=tr.resultReg, labelSymbol = arrayVarSymbol), null) } else { - resultRegister = tr.resultReg + resultRegister = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=tr.resultReg, labelSymbol = arrayVarSymbol), null) } } @@ -586,8 +588,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val tr = translateExpression(binExpr.left) addToResult(result, tr, tr.resultReg, -1) val opcode = if (notEquals) Opcode.SNZ else Opcode.SZ - addInstr(result, IRInstruction(opcode, vmDt, reg1 = tr.resultReg, reg2 = tr.resultReg), null) - ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() + addInstr(result, IRInstruction(opcode, vmDt, reg1 = resultReg, reg2 = tr.resultReg), null) + ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } else { val leftTr = translateExpression(binExpr.left) addToResult(result, leftTr, leftTr.resultReg, -1) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 072a1e25e..d8f5a13a6 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -6,11 +6,9 @@ import prog8.ast.Program import prog8.ast.base.AstException import prog8.ast.expressions.Expression import prog8.ast.expressions.NumericLiteral -import prog8.ast.printProgram import prog8.ast.statements.Directive import prog8.code.SymbolTableMaker import prog8.code.ast.PtProgram -import prog8.code.ast.printAst import prog8.code.core.* import prog8.code.target.* import prog8.codegen.vm.VmCodeGen @@ -117,10 +115,10 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { args.errors.report() val intermediateAst = IntermediateAstMaker(program, compilationOptions).transform() - println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************") - printProgram(program) - println("*********** AST RIGHT BEFORE ASM GENERATION *************") - printAst(intermediateAst, ::println) +// println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************") +// printProgram(program) +// println("*********** AST RIGHT BEFORE ASM GENERATION *************") +// printAst(intermediateAst, ::println) if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) { System.err.println("Error in codegeneration or assembler") diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4c6e27541..ea9cc158c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,9 +3,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- fix IR/VM crashing in bouncegfx and textelite - bouncegfx is larger than with 8.10 -- reduce the usage of register.nextFree() in IR codegen - get rid of all the require() checks that test result regs to be different ... diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index 3ad6795fd..998853e48 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -20,6 +20,7 @@ Instruction set is mostly a load/store architecture, there are few instructions Most instructions have an associated data type 'b','w','f'. (omitting it defaults to 'b' - byte). Currently NO support for 24 or 32 bits integers. Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions. +Instructions taking more than 1 register cannot take the same register multiple times! (to avoid confusing different datatypes) LOAD/STORE @@ -707,6 +708,7 @@ data class IRInstruction( require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"} require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"} require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"} + if(reg1!=null && reg2!=null) require(reg1!=reg2) {"reg1 must not be same as reg2"} // note: this is ok for fpRegs as these are always the same type if(value!=null && opcode !in OpcodesWithMemoryAddressAsValue) { when (type) { IRDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}