diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index cd4f60d84..0f1760fe3 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -330,10 +330,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe addToResult(result, msbTr, msbTr.resultReg, -1) val lsbTr = exprGen.translateExpression(call.args[1]) addToResult(result, lsbTr, lsbTr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1 = lsbTr.resultReg, reg2 = msbTr.resultReg) + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultReg, reg2 = lsbTr.resultReg, reg3 = msbTr.resultReg) } - return ExpressionCodeResult(result, IRDataType.WORD, lsbTr.resultReg, -1) + return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1) } private fun funcClamp(call: PtBuiltinFunctionCall): ExpressionCodeResult { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 1dbe1173f..7684c8a88 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -166,13 +166,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { require(vmDt==IRDataType.WORD) val arrayLength = codeGen.symbolTable.getLength(arrayIx.variable.name) resultRegister = codeGen.registers.nextFree() + val finalResultReg = codeGen.registers.nextFree() if(arrayIx.index is PtNumber) { val memOffset = (arrayIx.index as PtNumber).number.toInt() result += IRCodeChunk(null, null).also { val tmpRegMsb = codeGen.registers.nextFree() it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb+$memOffset") it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=tmpRegMsb, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb+$memOffset") - it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=tmpRegMsb) + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=finalResultReg, reg2=resultRegister, reg3=tmpRegMsb) } } else { val tr = translateExpression(arrayIx.index) @@ -181,10 +182,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val tmpRegMsb = codeGen.registers.nextFree() it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=resultRegister, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_lsb") it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2 = tr.resultReg, immediate = arrayLength, labelSymbol= "${arrayVarSymbol}_msb") - it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=tmpRegMsb) + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=finalResultReg, reg2=resultRegister, reg3=tmpRegMsb) } } - return ExpressionCodeResult(result, vmDt, resultRegister, -1) + return ExpressionCodeResult(result, vmDt, finalResultReg, -1) } var resultFpRegister = -1 @@ -454,6 +455,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { greaterEquals: Boolean ): ExpressionCodeResult { val result = mutableListOf() + val cmpResultReg = codeGen.registers.nextFree() if(vmDt==IRDataType.FLOAT) { val leftTr = translateExpression(binExpr.left) addToResult(result, leftTr, -1, leftTr.resultFpReg) @@ -468,8 +470,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } else { if (greaterEquals) Opcode.SGE else Opcode.SGT } - addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null) - return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1) + addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1=cmpResultReg, reg2 = resultRegister, reg3 = zeroRegister), null) + return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultReg, -1) } else { if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) { throw AssemblyError("str compares should have been replaced with builtin function call to do the compare") @@ -483,8 +485,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } else { if (greaterEquals) Opcode.SGE else Opcode.SGT } - addInstr(result, IRInstruction(ins, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg), null) - return ExpressionCodeResult(result, IRDataType.BYTE, leftTr.resultReg, -1) + addInstr(result, IRInstruction(ins, vmDt, reg1=cmpResultReg, reg2 = leftTr.resultReg, reg3 = rightTr.resultReg), null) + return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultReg, -1) } } } @@ -496,6 +498,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { lessEquals: Boolean ): ExpressionCodeResult { val result = mutableListOf() + val cmpResultRegister = codeGen.registers.nextFree() if(vmDt==IRDataType.FLOAT) { val leftTr = translateExpression(binExpr.left) addToResult(result, leftTr, -1, leftTr.resultFpReg) @@ -510,8 +513,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } else { if (lessEquals) Opcode.SLE else Opcode.SLT } - addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null) - return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1) + addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1=cmpResultRegister, reg2 = resultRegister, reg3 = zeroRegister), null) + return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultRegister, -1) } else { if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) { throw AssemblyError("str compares should have been replaced with builtin function call to do the compare") @@ -525,8 +528,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } else { if (lessEquals) Opcode.SLE else Opcode.SLT } - addInstr(result, IRInstruction(ins, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg), null) - return ExpressionCodeResult(result, IRDataType.BYTE, leftTr.resultReg, -1) + addInstr(result, IRInstruction(ins, vmDt, reg1=cmpResultRegister, reg2 = leftTr.resultReg, reg3 = rightTr.resultReg), null) + return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultRegister, -1) } } } @@ -568,8 +571,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val rightTr = translateExpression(binExpr.right) addToResult(result, rightTr, rightTr.resultReg, -1) val opcode = if (notEquals) Opcode.SNE else Opcode.SEQ - addInstr(result, IRInstruction(opcode, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg), null) - ExpressionCodeResult(result, IRDataType.BYTE, leftTr.resultReg, -1) + val resultReg = codeGen.registers.nextFree() + addInstr(result, IRInstruction(opcode, vmDt, reg1 = resultReg, reg2 = leftTr.resultReg, reg3 = rightTr.resultReg), null) + ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) } } } @@ -1239,6 +1243,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { ): MutableList { val result = mutableListOf() val valueReg = codeGen.registers.nextFree() + val cmpResultReg = codeGen.registers.nextFree() if(operand is PtNumber) { val numberReg = codeGen.registers.nextFree() if (knownAddress != null) { @@ -1246,16 +1251,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = knownAddress) it += IRInstruction(Opcode.LOAD, vmDt, reg1=numberReg, immediate = operand.number.toInt()) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = valueReg, reg2 = numberReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueReg, address = knownAddress) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = cmpResultReg, reg2 = valueReg, reg3 = numberReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = knownAddress) } } else { // in-place modify a symbol (variable) result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) it += IRInstruction(Opcode.LOAD, vmDt, reg1=numberReg, immediate = operand.number.toInt()) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = valueReg, reg2 = numberReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = numberReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) } } } else { @@ -1265,15 +1270,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { // in-place modify a memory location result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = knownAddress) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = valueReg, reg2 = tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueReg, address = knownAddress) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = knownAddress) } } else { // in-place modify a symbol (variable) result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) - it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = valueReg, reg2 = tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2 = valueReg, reg3 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) } } } @@ -1292,6 +1297,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val zeroReg = codeGen.registers.nextFree() if(operand is PtNumber) { val numberReg = codeGen.registers.nextFreeFloat() + val cmpResultReg = codeGen.registers.nextFree() if (knownAddress != null) { // in-place modify a memory location result += IRCodeChunk(null, null).also { @@ -1299,8 +1305,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number.toFloat()) it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg) it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpReg, reg2=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = knownAddress) } } else { @@ -1310,13 +1316,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { it += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = numberReg, immediateFp = operand.number.toFloat()) it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = numberReg) it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpReg, reg2=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) } } } else { val tr = translateExpression(operand) + val cmpResultReg = codeGen.registers.nextFree() addToResult(result, tr, -1, tr.resultFpReg) if (knownAddress != null) { // in-place modify a memory location @@ -1324,8 +1331,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, address = knownAddress) it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpReg, reg2=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, address = knownAddress) } } else { @@ -1334,8 +1341,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, immediate = 0) - it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpReg, reg2=zeroReg) - it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpResultReg, reg2=cmpReg, reg3=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpResultReg, fpReg1 = valueReg) it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 4d1b987f7..49ab1b0f9 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -177,6 +177,7 @@ class IRCodeGen( old.type, old.reg1, old.reg2, + old.reg3, old.fpReg1, old.fpReg2, immediate = immediateValue, @@ -476,10 +477,11 @@ class IRCodeGen( result += IRCodeChunk(loopLabel, null).also { val tmpRegLsb = registers.nextFree() val tmpRegMsb = registers.nextFree() + val concatReg = registers.nextFree() it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_lsb") it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_msb") - it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb) - it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol) + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=concatReg, reg2=tmpRegLsb, reg3=tmpRegMsb) + it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=concatReg, labelSymbol = loopvarSymbol) } result += translateNode(forLoop.statements) result += IRCodeChunk(null, null).also { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 6c9a6759a..6a844603e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,6 @@ TODO ==== -- IR: instructions that do type conversion (SZ etc, CONCAT, SGN) should put the result in a DIFFERENT register. - IR: reduce the number of branch instructions (gradually), replace with CMP(I) + status branch instruction ... diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index 97bfafb0f..6a4313dc4 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -99,16 +99,16 @@ bles reg1, value, address - jump to location in program given by l ( NOTE: there are no bltr/bler instructions because these are equivalent to bgtr/bger with the register operands swapped around.) sz reg1, reg2 - set reg1=1 if reg2==0, else 0 snz reg1, reg2 - set reg1=1 if reg2!=0, else 0 -seq reg1, reg2 - set reg1=1 if reg1 == reg2, else 0 -sne reg1, reg2 - set reg1=1 if reg1 != reg2, else 0 -slt reg1, reg2 - set reg1=1 if reg1 < reg2 (unsigned), else 0 -slts reg1, reg2 - set reg1=1 if reg1 < reg2 (signed), else 0 -sle reg1, reg2 - set reg1=1 if reg1 <= reg2 (unsigned), else 0 -sles reg1, reg2 - set reg1=1 if reg1 <= reg2 (signed), else 0 -sgt reg1, reg2 - set reg1=1 if reg1 > reg2 (unsigned), else 0 -sgts reg1, reg2 - set reg1=1 if reg1 > reg2 (signed), else 0 -sge reg1, reg2 - set reg1=1 if reg1 >= reg2 (unsigned), else 0 -sges reg1, reg2 - set reg1=1 if reg1 >= reg2 (signed), else 0 +seq reg1, reg2, reg3 - set reg1=1 if reg2 == reg3, else 0 +sne reg1, reg2, reg3 - set reg1=1 if reg2 != reg3, else 0 +slt reg1, reg2, reg3 - set reg1=1 if reg2 < reg3 (unsigned), else 0 +slts reg1, reg2, reg3 - set reg1=1 if reg2 < reg3 (signed), else 0 +sle reg1, reg2, reg3 - set reg1=1 if reg2 <= reg3 (unsigned), else 0 +sles reg1, reg2, reg3 - set reg1=1 if reg2 <= reg3 (signed), else 0 +sgt reg1, reg2, reg3 - set reg1=1 if reg2 > reg3 (unsigned), else 0 +sgts reg1, reg2, reg3 - set reg1=1 if reg2 > reg3 (signed), else 0 +sge reg1, reg2, reg3 - set reg1=1 if reg2 >= reg3 (unsigned), else 0 +sges reg1, reg2, reg3 - set reg1=1 if reg2 >= reg3 (signed), else 0 (note: on the M68k these instructions will set all bits to 1 (so value=-1 instead of 1), but the boolean logic here requires it to be 0 or 1 in this IR) @@ -220,7 +220,7 @@ sec - set Carry status bit nop - do nothing breakpoint - trigger a breakpoint msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs) -concat [b, w] reg1, reg2 - reg1 = concatenated lsb/lsw of reg1 (as lsb) and lsb/lsw of reg2 (as msb) into word or int (int not yet implemented; requires 32bits regs) +concat [b, w] reg1, reg2, reg3 - reg1.w = concatenated lsb/lsw of reg2 (as lsb) and lsb/lsw of reg3 (as msb) into word or int (int not yet implemented; requires 32bits regs) push [b, w, f] reg1 - push value in reg1 on the stack pop [b, w, f] reg1 - pop value from stack into reg1 */ @@ -454,6 +454,7 @@ enum class OperandDirection { data class InstructionFormat(val datatype: IRDataType?, val reg1: OperandDirection, val reg2: OperandDirection, + val reg3: OperandDirection, val fpReg1: OperandDirection, val fpReg2: OperandDirection, val address: OperandDirection, @@ -466,6 +467,7 @@ data class InstructionFormat(val datatype: IRDataType?, for(part in spec.split('|').map{ it.trim() }) { var reg1 = OperandDirection.UNUSED var reg2 = OperandDirection.UNUSED + var reg3 = OperandDirection.UNUSED var fpreg1 = OperandDirection.UNUSED var fpreg2 = OperandDirection.UNUSED var address = OperandDirection.UNUSED @@ -480,6 +482,7 @@ data class InstructionFormat(val datatype: IRDataType?, ">r1" -> reg1 = OperandDirection.WRITE "<>r1" -> reg1 = OperandDirection.READWRITE " reg2 = OperandDirection.READ + " reg3 = OperandDirection.READ " fpreg1 = OperandDirection.READ ">fr1" -> fpreg1 = OperandDirection.WRITE "<>fr1" -> fpreg1 = OperandDirection.READWRITE @@ -496,13 +499,13 @@ data class InstructionFormat(val datatype: IRDataType?, } if(typespec=="N") - result[null] = InstructionFormat(null, reg1, reg2, fpreg1, fpreg2, address, immediate, funcCall, sysCall) + result[null] = InstructionFormat(null, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) if('B' in typespec) - result[IRDataType.BYTE] = InstructionFormat(IRDataType.BYTE, reg1, reg2, fpreg1, fpreg2, address, immediate, funcCall, sysCall) + result[IRDataType.BYTE] = InstructionFormat(IRDataType.BYTE, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) if('W' in typespec) - result[IRDataType.WORD] = InstructionFormat(IRDataType.WORD, reg1, reg2, fpreg1, fpreg2, address, immediate, funcCall, sysCall) + result[IRDataType.WORD] = InstructionFormat(IRDataType.WORD, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) if('F' in typespec) - result[IRDataType.FLOAT] = InstructionFormat(IRDataType.FLOAT, reg1, reg2, fpreg1, fpreg2, address, immediate, funcCall, sysCall) + result[IRDataType.FLOAT] = InstructionFormat(IRDataType.FLOAT, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) } return result } @@ -566,16 +569,16 @@ val instructionFormats = mutableMapOf( Opcode.BLES to InstructionFormat.from("BW,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1 | F,<>fr1"), Opcode.INCM to InstructionFormat.from("BW,<>a | F,<>a"), Opcode.DEC to InstructionFormat.from("BW,<>r1 | F,<>fr1"), @@ -663,7 +666,7 @@ val instructionFormats = mutableMapOf( Opcode.MSIG to InstructionFormat.from("BW,>r1,r1 | F,>fr1"), - Opcode.CONCAT to InstructionFormat.from("BW,<>r1,r1, throw IllegalArgumentException("reg2 can only be read") } + when (this.reg3direction) { + OperandDirection.UNUSED -> {} + OperandDirection.READ -> { + writeRegsCounts[this.reg3!!] = writeRegsCounts.getValue(this.reg3)+1 + if(type!=null) { + var types = regsTypes[this.reg3] + if(types==null) types = mutableSetOf() + types += type + regsTypes[this.reg3] = types + } + } + else -> throw IllegalArgumentException("reg3 can only be read") + } when (this.fpReg1direction) { OperandDirection.UNUSED -> {} OperandDirection.READ -> { @@ -927,6 +951,10 @@ data class IRInstruction( result.add("r$it") result.add(",") } + reg3?.let { + result.add("r$it") + result.add(",") + } fpReg1?.let { result.add("fr$it") result.add(",") diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index 472104780..728115fa9 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -115,6 +115,7 @@ fun parseIRCodeLine(line: String): Either { val operands = if(rest.isBlank()) emptyList() else rest.split(",").map{ it.trim() }.toMutableList() var reg1: Int? = null var reg2: Int? = null + var reg3: Int? = null var fpReg1: Int? = null var fpReg2: Int? = null var immediateInt: Int? = null @@ -143,6 +144,7 @@ fun parseIRCodeLine(line: String): Either { else if (oper[0] in "rR") { if (reg1 == null) reg1 = oper.substring(1).toInt() else if (reg2 == null) reg2 = oper.substring(1).toInt() + else if (reg3 == null) reg3 = oper.substring(1).toInt() else throw IRParseException("too many register operands") } else if (oper[0] in "fF" && oper[1] in "rR") { if (fpReg1 == null) fpReg1 = oper.substring(2).toInt() @@ -179,6 +181,8 @@ fun parseIRCodeLine(line: String): Either { throw IRParseException("needs reg1 for $line") if(format.reg2!=OperandDirection.UNUSED && reg2==null) throw IRParseException("needs reg2 for $line") + if(format.reg3!=OperandDirection.UNUSED && reg3==null) + throw IRParseException("needs reg3 for $line") if(format.fpReg1!=OperandDirection.UNUSED && fpReg1==null) throw IRParseException("needs fpReg1 for $line") if(format.fpReg2!=OperandDirection.UNUSED && fpReg2==null) @@ -189,6 +193,8 @@ fun parseIRCodeLine(line: String): Either { throw IRParseException("invalid reg1 for $line") if(format.reg2==OperandDirection.UNUSED && reg2!=null) throw IRParseException("invalid reg2 for $line") + if(format.reg3==OperandDirection.UNUSED && reg3!=null) + throw IRParseException("invalid reg3 for $line") if(format.fpReg1==OperandDirection.UNUSED && fpReg1!=null) throw IRParseException("invalid fpReg1 for $line") if(format.fpReg2==OperandDirection.UNUSED && fpReg2!=null) @@ -218,7 +224,7 @@ fun parseIRCodeLine(line: String): Either { throw IRParseException("labelsymbol confused with register?: $labelSymbol") } - return left(IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, immediateInt, immediateFp, address, labelSymbol = labelSymbol)) + return left(IRInstruction(opcode, type, reg1, reg2, reg3, fpReg1, fpReg2, immediateInt, immediateFp, address, labelSymbol = labelSymbol)) } private class ParsedCall( diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index f7761f991..d639f26c2 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -808,14 +808,24 @@ class VirtualMachine(irProgram: IRProgram) { } private fun InsSZ(i: IRInstruction) { - val (_: Int, right: Int) = getSetOnConditionOperands(i) + val right = when(i.type) { + IRDataType.BYTE -> registers.getSB(i.reg2!!).toInt() + IRDataType.WORD -> registers.getSW(i.reg2!!).toInt() + IRDataType.FLOAT -> throw IllegalArgumentException("can't use float here") + null -> throw IllegalArgumentException("need type for branch instruction") + } val value = if(right==0) 1 else 0 setResultReg(i.reg1!!, value, i.type!!) nextPc() } private fun InsSNZ(i: IRInstruction) { - val (_: Int, right: Int) = getSetOnConditionOperands(i) + val right = when(i.type) { + IRDataType.BYTE -> registers.getSB(i.reg2!!).toInt() + IRDataType.WORD -> registers.getSW(i.reg2!!).toInt() + IRDataType.FLOAT -> throw IllegalArgumentException("can't use float here") + null -> throw IllegalArgumentException("need type for branch instruction") + } val value = if(right!=0) 1 else 0 setResultReg(i.reg1!!, value, i.type!!) nextPc() @@ -889,7 +899,6 @@ class VirtualMachine(irProgram: IRProgram) { val value = if(left>=right) 1 else 0 setResultReg(i.reg1!!, value, i.type!!) nextPc() - } private fun InsINC(i: IRInstruction) { @@ -2106,8 +2115,8 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsCONCAT(i: IRInstruction) { when(i.type!!) { IRDataType.BYTE -> { - val lsb = registers.getUB(i.reg1!!) - val msb = registers.getUB(i.reg2!!) + val lsb = registers.getUB(i.reg2!!) + val msb = registers.getUB(i.reg3!!) registers.setUW(i.reg1!!, ((msb.toInt() shl 8) or lsb.toInt()).toUShort()) } IRDataType.WORD -> throw IllegalArgumentException("concat.w not yet supported, requires 32-bits registers") @@ -2305,8 +2314,8 @@ class VirtualMachine(irProgram: IRProgram) { private fun getSetOnConditionOperands(ins: IRInstruction): Pair { return when(ins.type) { - IRDataType.BYTE -> Pair(registers.getSB(ins.reg1!!).toInt(), registers.getSB(ins.reg2!!).toInt()) - IRDataType.WORD -> Pair(registers.getSW(ins.reg1!!).toInt(), registers.getSW(ins.reg2!!).toInt()) + IRDataType.BYTE -> Pair(registers.getSB(ins.reg2!!).toInt(), registers.getSB(ins.reg3!!).toInt()) + IRDataType.WORD -> Pair(registers.getSW(ins.reg2!!).toInt(), registers.getSW(ins.reg3!!).toInt()) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") } @@ -2316,8 +2325,8 @@ class VirtualMachine(irProgram: IRProgram) { private fun getSetOnConditionOperandsU(ins: IRInstruction): Pair { return when(ins.type) { - IRDataType.BYTE -> Pair(registers.getUB(ins.reg1!!).toUInt(), registers.getUB(ins.reg2!!).toUInt()) - IRDataType.WORD -> Pair(registers.getUW(ins.reg1!!).toUInt(), registers.getUW(ins.reg2!!).toUInt()) + IRDataType.BYTE -> Pair(registers.getUB(ins.reg2!!).toUInt(), registers.getUB(ins.reg3!!).toUInt()) + IRDataType.WORD -> Pair(registers.getUW(ins.reg2!!).toUInt(), registers.getUW(ins.reg3!!).toUInt()) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") }