IR: sXX, CONCAT instructions now use 3 register format

This commit is contained in:
Irmen de Jong 2023-07-20 23:58:52 +02:00
parent 7136b33f2e
commit c7d54570cc
7 changed files with 122 additions and 70 deletions

View File

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

View File

@ -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<IRCodeChunkBase>()
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<IRCodeChunkBase>()
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<IRCodeChunkBase> {
val result = mutableListOf<IRCodeChunkBase>()
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)
}
}

View File

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

View File

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

View File

@ -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
"<r2" -> reg2 = OperandDirection.READ
"<r3" -> reg3 = OperandDirection.READ
"<fr1" -> 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,<i,<a"),
Opcode.SZ to InstructionFormat.from("BW,>r1,<r2"),
Opcode.SNZ to InstructionFormat.from("BW,>r1,<r2"),
Opcode.SEQ to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SNE to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLT to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLTS to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGT to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGTS to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLE to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SLES to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGE to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SGES to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.SEQ to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SNE to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SLT to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SLTS to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SGT to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SGTS to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SLE to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SLES to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SGE to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.SGES to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.INC to InstructionFormat.from("BW,<>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,<r2"),
Opcode.PUSH to InstructionFormat.from("BW,<r1 | F,<fr1"),
Opcode.POP to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.CONCAT to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.CONCAT to InstructionFormat.from("BW,<>r1,<r2,<r3"),
Opcode.CLC to InstructionFormat.from("N"),
Opcode.SEC to InstructionFormat.from("N"),
Opcode.BREAKPOINT to InstructionFormat.from("N"),
@ -683,6 +686,7 @@ data class IRInstruction(
val type: IRDataType?=null,
val reg1: Int?=null, // 0-$ffff
val reg2: Int?=null, // 0-$ffff
val reg3: Int?=null, // 0-$ffff
val fpReg1: Int?=null, // 0-$ffff
val fpReg2: Int?=null, // 0-$ffff
val immediate: Int?=null, // 0-$ff or $ffff if word
@ -696,6 +700,7 @@ data class IRInstruction(
// This knowledge is useful in IL assembly optimizers to see how registers are used.
val reg1direction: OperandDirection
val reg2direction: OperandDirection
val reg3direction: OperandDirection
val fpReg1direction: OperandDirection
val fpReg2direction: OperandDirection
@ -703,9 +708,12 @@ data class IRInstruction(
require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"}
require(reg1==null || reg1 in 0..65536) {"reg1 out of bounds"}
require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"}
require(reg3==null || reg3 in 0..65536) {"reg3 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(reg1!=null && reg3!=null) require(reg1!=reg3) {"reg1 must not be same as reg3"} // note: this is ok for fpRegs as these are always the same type
if(reg2!=null && reg3!=null) require(reg2!=reg3) {"reg2 must not be same as reg3"} // note: this is ok for fpRegs as these are always the same type
val formats = instructionFormats.getValue(opcode)
require (type != null || formats.containsKey(null)) { "missing type" }
@ -713,10 +721,12 @@ data class IRInstruction(
val format = formats.getOrElse(type) { throw IllegalArgumentException("type $type invalid for $opcode") }
if(format.reg1!=OperandDirection.UNUSED) require(reg1!=null) { "missing reg1" }
if(format.reg2!=OperandDirection.UNUSED) require(reg2!=null) { "missing reg2" }
if(format.reg3!=OperandDirection.UNUSED) require(reg3!=null) { "missing reg3" }
if(format.fpReg1!=OperandDirection.UNUSED) require(fpReg1!=null) { "missing fpReg1" }
if(format.fpReg2!=OperandDirection.UNUSED) require(fpReg2!=null) { "missing fpReg2" }
if(format.reg1==OperandDirection.UNUSED) require(reg1==null) { "invalid reg1" }
if(format.reg2==OperandDirection.UNUSED) require(reg2==null) { "invalid reg2" }
if(format.reg3==OperandDirection.UNUSED) require(reg3==null) { "invalid reg3" }
if(format.fpReg1==OperandDirection.UNUSED) require(fpReg1==null) { "invalid fpReg1" }
if(format.fpReg2==OperandDirection.UNUSED) require(fpReg2==null) { "invalid fpReg2" }
if(format.immediate) {
@ -747,6 +757,7 @@ data class IRInstruction(
reg1direction = format.reg1
reg2direction = format.reg2
reg3direction = format.reg3
fpReg1direction = format.fpReg1
fpReg2direction = format.fpReg2
@ -814,6 +825,19 @@ data class IRInstruction(
}
else -> 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(",")

View File

@ -115,6 +115,7 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
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<IRInstruction, String> {
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<IRInstruction, String> {
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<IRInstruction, String> {
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<IRInstruction, String> {
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(

View File

@ -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<Int, Int> {
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<UInt, UInt> {
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")
}