IR: don't allow to have 2 same registers on instructions

This commit is contained in:
Irmen de Jong 2023-03-14 00:45:41 +01:00
parent dc316fd7b4
commit 199adbbcf0
5 changed files with 31 additions and 25 deletions

View File

@ -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<IRCodeChunkBase>()
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<IRCodeChunkBase>()
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 {

View File

@ -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)

View File

@ -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")

View File

@ -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
...

View File

@ -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"}