mirror of
https://github.com/irmen/prog8.git
synced 2024-07-06 13:29:00 +00:00
tweaking IR instruction set branch instructions
This commit is contained in:
parent
ccdf05e922
commit
9b952fbc44
@ -165,7 +165,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=compareReg, reg2=tr.resultReg)
|
||||
it += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=compareReg, immediate = 0x80)
|
||||
it += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1=compareReg, immediate = 0, labelSymbol = notNegativeLabel)
|
||||
it += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1=tr.resultReg)
|
||||
it += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=tr.resultReg)
|
||||
}
|
||||
@ -178,7 +178,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1=compareReg, reg2=tr.resultReg)
|
||||
it += IRInstruction(Opcode.AND, IRDataType.WORD, reg1=compareReg, immediate = 0x8000)
|
||||
it += IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
it += IRInstruction(Opcode.BEQ, IRDataType.WORD, reg1=compareReg, immediate = 0, labelSymbol = notNegativeLabel)
|
||||
it += IRInstruction(Opcode.NEG, IRDataType.WORD, reg1=tr.resultReg)
|
||||
}
|
||||
result += IRCodeChunk(notNegativeLabel, null)
|
||||
|
@ -566,9 +566,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, immediate = 1), null)
|
||||
addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=valueReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightTr.resultFpReg), null)
|
||||
if (notEquals) {
|
||||
addInstr(result, IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=valueReg, labelSymbol = label), null)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=valueReg, immediate = 0, labelSymbol = label), null)
|
||||
} else {
|
||||
addInstr(result, IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=valueReg, labelSymbol = label), null)
|
||||
addInstr(result, IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1=valueReg, immediate = 0, labelSymbol = label), null)
|
||||
}
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, immediate = 0), null)
|
||||
result += IRCodeChunk(label, null)
|
||||
|
@ -419,11 +419,9 @@ class IRCodeGen(
|
||||
} else {
|
||||
val skipLabel = createLabelName()
|
||||
val values = choice.values.children.map {it as PtNumber}
|
||||
val choiceReg = registers.nextFree()
|
||||
if(values.size==1) {
|
||||
val chunk = IRCodeChunk(null, null)
|
||||
chunk += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, immediate = values[0].number.toInt())
|
||||
chunk += IRInstruction(Opcode.BNE, valueDt, reg1=valueTr.resultReg, reg2=choiceReg, labelSymbol = skipLabel)
|
||||
chunk += IRInstruction(Opcode.BNE, valueDt, reg1=valueTr.resultReg, immediate = values[0].number.toInt(), labelSymbol = skipLabel)
|
||||
result += chunk
|
||||
result += translateNode(choice.statements)
|
||||
if(choice.statements.children.last() !is PtReturn)
|
||||
@ -432,8 +430,7 @@ class IRCodeGen(
|
||||
val matchLabel = createLabelName()
|
||||
val chunk = IRCodeChunk(null, null)
|
||||
for (value in values) {
|
||||
chunk += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, immediate = value.number.toInt())
|
||||
chunk += IRInstruction(Opcode.BEQ, valueDt, reg1=valueTr.resultReg, reg2=choiceReg, labelSymbol = matchLabel)
|
||||
chunk += IRInstruction(Opcode.BEQ, valueDt, reg1=valueTr.resultReg, immediate = value.number.toInt(), labelSymbol = matchLabel)
|
||||
}
|
||||
chunk += IRInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
||||
result += chunk
|
||||
@ -472,7 +469,7 @@ class IRCodeGen(
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
val chunk = IRCodeChunk(loopLabel, null)
|
||||
chunk += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = iterable.name)
|
||||
chunk += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
||||
chunk += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1=tmpReg, immediate = 0, labelSymbol = endLabel)
|
||||
chunk += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
result += chunk
|
||||
result += translateNode(forLoop.statements)
|
||||
@ -487,10 +484,8 @@ class IRCodeGen(
|
||||
val elementSize = program.memsizer.memorySize(elementDt)
|
||||
val lengthBytes = iterableVar.length!! * elementSize
|
||||
if(lengthBytes<256) {
|
||||
val lengthReg = registers.nextFree()
|
||||
val chunk = IRCodeChunk(null, null)
|
||||
chunk += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0)
|
||||
chunk += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, immediate = lengthBytes)
|
||||
result += chunk
|
||||
val chunk2 = IRCodeChunk(loopLabel, null)
|
||||
chunk2 += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
|
||||
@ -498,7 +493,7 @@ class IRCodeGen(
|
||||
result += chunk2
|
||||
result += translateNode(forLoop.statements)
|
||||
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel), null)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = lengthBytes, labelSymbol = loopLabel), null)
|
||||
} else if(lengthBytes==256) {
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
val chunk = IRCodeChunk(loopLabel, null)
|
||||
@ -507,7 +502,7 @@ class IRCodeGen(
|
||||
result += chunk
|
||||
result += translateNode(forLoop.statements)
|
||||
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
|
||||
addInstr(result, IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel), null)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = 0, labelSymbol = loopLabel), null)
|
||||
} else {
|
||||
throw AssemblyError("iterator length should never exceed 256")
|
||||
}
|
||||
@ -540,7 +535,7 @@ class IRCodeGen(
|
||||
addToResult(result, fromTr, fromTr.resultReg, -1)
|
||||
|
||||
val labelAfterFor = createLabelName()
|
||||
val greaterOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGTS else Opcode.BGT
|
||||
val greaterOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGTSR else Opcode.BGTR
|
||||
addInstr(result, IRInstruction(greaterOpcode, loopvarDtIr, fromTr.resultReg, toTr.resultReg, labelSymbol=labelAfterFor), null)
|
||||
|
||||
addInstr(result, IRInstruction(Opcode.STOREM, loopvarDtIr, reg1=fromTr.resultReg, labelSymbol=loopvarSymbol), null)
|
||||
@ -548,7 +543,7 @@ class IRCodeGen(
|
||||
result += addConstMem(loopvarDtIr, null, loopvarSymbol, step)
|
||||
addInstr(result, IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = fromTr.resultReg, labelSymbol = loopvarSymbol), null)
|
||||
// if endvalue >= index, iterate loop
|
||||
val branchOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGES else Opcode.BGE
|
||||
val branchOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGESR else Opcode.BGER
|
||||
addInstr(result, IRInstruction(branchOpcode, loopvarDtIr, reg1=toTr.resultReg, reg2=fromTr.resultReg, labelSymbol=loopLabel), null)
|
||||
|
||||
result += IRCodeChunk(labelAfterFor, null)
|
||||
@ -575,15 +570,8 @@ class IRCodeGen(
|
||||
if(step>0 && rangeEndUntyped<rangeStart || step<0 && rangeEndUntyped>rangeStart)
|
||||
throw AssemblyError("empty range")
|
||||
val rangeEndWrapped = if(loopvarDtIr==IRDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535
|
||||
val endvalueReg: Int
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val chunk = IRCodeChunk(null, null)
|
||||
if(rangeEndWrapped!=0) {
|
||||
endvalueReg = registers.nextFree()
|
||||
chunk += IRInstruction(Opcode.LOAD, loopvarDtIr, reg1 = endvalueReg, immediate = rangeEndWrapped)
|
||||
} else {
|
||||
endvalueReg = -1 // not used
|
||||
}
|
||||
chunk += IRInstruction(Opcode.LOAD, loopvarDtIr, reg1=indexReg, immediate = rangeStart)
|
||||
chunk += IRInstruction(Opcode.STOREM, loopvarDtIr, reg1=indexReg, labelSymbol=loopvarSymbol)
|
||||
result += chunk
|
||||
@ -591,11 +579,7 @@ class IRCodeGen(
|
||||
result += addConstMem(loopvarDtIr, null, loopvarSymbol, step)
|
||||
val chunk2 = IRCodeChunk(null, null)
|
||||
chunk2 += IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
||||
chunk2 += if(rangeEndWrapped==0) {
|
||||
IRInstruction(Opcode.BNZ, loopvarDtIr, reg1 = indexReg, labelSymbol = loopLabel)
|
||||
} else {
|
||||
IRInstruction(Opcode.BNE, loopvarDtIr, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
|
||||
}
|
||||
chunk2 += IRInstruction(Opcode.BNE, loopvarDtIr, reg1 = indexReg, immediate = rangeEndWrapped, labelSymbol = loopLabel)
|
||||
result += chunk2
|
||||
return result
|
||||
}
|
||||
@ -934,18 +918,18 @@ class IRCodeGen(
|
||||
|
||||
|
||||
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump, irDtLeft: IRDataType, signed: Boolean): MutableList<IRCodeChunkBase> {
|
||||
val conditionBinExpr = ifElse.condition as? PtBinaryExpression
|
||||
val condition = ifElse.condition as? PtBinaryExpression
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(conditionBinExpr==null) {
|
||||
if(condition==null) {
|
||||
if(irDtLeft==IRDataType.FLOAT)
|
||||
throw AssemblyError("condition value should not be float")
|
||||
ifNonZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
||||
return result
|
||||
} else {
|
||||
if (irDtLeft == IRDataType.FLOAT) {
|
||||
val leftTr = expressionEval.translateExpression(conditionBinExpr.left)
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
||||
val rightTr = expressionEval.translateExpression(conditionBinExpr.right)
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
val compResultReg = registers.nextFree()
|
||||
@ -956,40 +940,25 @@ class IRCodeGen(
|
||||
fpReg1 = leftTr.resultFpReg,
|
||||
fpReg2 = rightTr.resultFpReg
|
||||
)
|
||||
val gotoOpcode = when (conditionBinExpr.operator) {
|
||||
"==" -> Opcode.BZ
|
||||
"!=" -> Opcode.BNZ
|
||||
"<" -> Opcode.BLEZS
|
||||
">" -> Opcode.BGEZS
|
||||
"<=" -> Opcode.BLZS
|
||||
">=" -> Opcode.BGZS
|
||||
val gotoOpcode = when (condition.operator) {
|
||||
"==" -> Opcode.BEQ
|
||||
"!=" -> Opcode.BNE
|
||||
"<" -> Opcode.BLTS
|
||||
">" -> Opcode.BGTS
|
||||
"<=" -> Opcode.BLES
|
||||
">=" -> Opcode.BGES
|
||||
else -> throw AssemblyError("weird operator")
|
||||
}
|
||||
it += if (goto.address != null)
|
||||
IRInstruction(
|
||||
gotoOpcode,
|
||||
IRDataType.BYTE,
|
||||
reg1 = compResultReg,
|
||||
address = goto.address?.toInt()
|
||||
)
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, address = goto.address?.toInt())
|
||||
else if (goto.generatedLabel != null)
|
||||
IRInstruction(
|
||||
gotoOpcode,
|
||||
IRDataType.BYTE,
|
||||
reg1 = compResultReg,
|
||||
labelSymbol = goto.generatedLabel
|
||||
)
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = goto.generatedLabel)
|
||||
else
|
||||
IRInstruction(
|
||||
gotoOpcode,
|
||||
IRDataType.BYTE,
|
||||
reg1 = compResultReg,
|
||||
labelSymbol = goto.identifier!!.name
|
||||
)
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = goto.identifier!!.name)
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
val rightConst = conditionBinExpr.right.asConstInteger()
|
||||
val rightConst = condition.right.asConstInteger()
|
||||
if (rightConst == 0)
|
||||
ifZeroIntThenJump(result, ifElse, signed, irDtLeft, goto)
|
||||
else {
|
||||
@ -1011,20 +980,20 @@ class IRCodeGen(
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val opcode = when (condition.operator) {
|
||||
"==" -> Opcode.BZ
|
||||
"!=" -> Opcode.BNZ
|
||||
"<" -> if (signed) Opcode.BLZS else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
||||
">" -> if (signed) Opcode.BGZS else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
|
||||
"<=" -> if (signed) Opcode.BLEZS else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
|
||||
">=" -> if (signed) Opcode.BGEZS else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
|
||||
"==" -> Opcode.BEQ
|
||||
"!=" -> Opcode.BNE
|
||||
"<" -> if (signed) Opcode.BLTS else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
||||
">" -> if (signed) Opcode.BGTS else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
|
||||
"<=" -> if (signed) Opcode.BLES else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
|
||||
">=" -> if (signed) Opcode.BGES else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
if (goto.address != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, address = goto.address?.toInt()), null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, immediate = 0, address = goto.address?.toInt()), null)
|
||||
else if (goto.generatedLabel != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, labelSymbol = goto.generatedLabel), null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, immediate = 0, labelSymbol = goto.generatedLabel), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, labelSymbol = goto.identifier!!.name), null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, immediate = 0, labelSymbol = goto.identifier!!.name), null)
|
||||
}
|
||||
|
||||
private fun ifNonZeroIntThenJump(
|
||||
@ -1034,65 +1003,88 @@ class IRCodeGen(
|
||||
irDtLeft: IRDataType,
|
||||
goto: PtJump
|
||||
) {
|
||||
val conditionBinExpr = ifElse.condition as? PtBinaryExpression
|
||||
if(conditionBinExpr==null) {
|
||||
val condition = ifElse.condition as? PtBinaryExpression
|
||||
if(condition==null) {
|
||||
val tr = expressionEval.translateExpression(ifElse.condition)
|
||||
result += tr.chunks
|
||||
if (goto.address != null)
|
||||
addInstr(result, IRInstruction(Opcode.BNZ, irDtLeft, reg1 = tr.resultReg, address = goto.address?.toInt()), null)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, irDtLeft, reg1 = tr.resultReg, immediate = 0, address = goto.address?.toInt()), null)
|
||||
else if (goto.generatedLabel != null)
|
||||
addInstr(result, IRInstruction(Opcode.BNZ, irDtLeft, reg1 = tr.resultReg, labelSymbol = goto.generatedLabel), null)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, irDtLeft, reg1 = tr.resultReg, immediate = 0, labelSymbol = goto.generatedLabel), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(Opcode.BNZ, irDtLeft, reg1 = tr.resultReg, labelSymbol = goto.identifier!!.name), null)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, irDtLeft, reg1 = tr.resultReg, immediate = 0, labelSymbol = goto.identifier!!.name), null)
|
||||
} else {
|
||||
val leftTr = expressionEval.translateExpression(conditionBinExpr.left)
|
||||
|
||||
// TODO use immediate branch instructions if the value is constant
|
||||
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = expressionEval.translateExpression(conditionBinExpr.right)
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
val opcode: Opcode
|
||||
val firstReg: Int
|
||||
val secondReg: Int
|
||||
when (conditionBinExpr.operator) {
|
||||
"==" -> {
|
||||
opcode = Opcode.BEQ
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
val number = (condition.right as? PtNumber)?.number?.toInt()
|
||||
if(number!=null) {
|
||||
val firstReg = leftTr.resultReg
|
||||
val opcode = when (condition.operator) {
|
||||
"==" -> Opcode.BEQ
|
||||
"!=" -> Opcode.BNE
|
||||
"<" -> if(signed) Opcode.BLTS else Opcode.BLT
|
||||
">" -> if(signed) Opcode.BGTS else Opcode.BGT
|
||||
"<=" -> if(signed) Opcode.BLES else Opcode.BLE
|
||||
">=" -> if(signed) Opcode.BGES else Opcode.BGE
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
"!=" -> {
|
||||
opcode = Opcode.BNE
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
if (goto.address != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, immediate = number, address = goto.address?.toInt()), null)
|
||||
else if (goto.generatedLabel != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, immediate = number, labelSymbol = goto.generatedLabel), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, immediate = number, labelSymbol = goto.identifier!!.name), null)
|
||||
} else {
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
val firstReg: Int
|
||||
val secondReg: Int
|
||||
when (condition.operator) {
|
||||
"==" -> {
|
||||
opcode = Opcode.BEQR
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
}
|
||||
"!=" -> {
|
||||
opcode = Opcode.BNER
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
}
|
||||
"<" -> {
|
||||
// swapped '>'
|
||||
opcode = if (signed) Opcode.BGTSR else Opcode.BGTR
|
||||
firstReg = rightTr.resultReg
|
||||
secondReg = leftTr.resultReg
|
||||
}
|
||||
">" -> {
|
||||
opcode = if (signed) Opcode.BGTSR else Opcode.BGTR
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
}
|
||||
"<=" -> {
|
||||
// swapped '>='
|
||||
opcode = if (signed) Opcode.BGESR else Opcode.BGER
|
||||
firstReg = rightTr.resultReg
|
||||
secondReg = leftTr.resultReg
|
||||
}
|
||||
">=" -> {
|
||||
opcode = if (signed) Opcode.BGESR else Opcode.BGER
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
}
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
"<" -> {
|
||||
// swapped '>'
|
||||
opcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||
firstReg = rightTr.resultReg
|
||||
secondReg = leftTr.resultReg
|
||||
}
|
||||
">" -> {
|
||||
opcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
}
|
||||
"<=" -> {
|
||||
// swapped '>='
|
||||
opcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||
firstReg = rightTr.resultReg
|
||||
secondReg = leftTr.resultReg
|
||||
}
|
||||
">=" -> {
|
||||
opcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||
firstReg = leftTr.resultReg
|
||||
secondReg = rightTr.resultReg
|
||||
}
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
if (goto.address != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, address = goto.address?.toInt()), null)
|
||||
else if (goto.generatedLabel != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.generatedLabel), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.identifier!!.name), null)
|
||||
}
|
||||
if (goto.address != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, address = goto.address?.toInt()), null)
|
||||
else if (goto.generatedLabel != null)
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.generatedLabel), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.identifier!!.name), null)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1113,12 +1105,12 @@ class IRCodeGen(
|
||||
it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=compResultReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightFpReg)
|
||||
}
|
||||
elseBranch = when (condition.operator) {
|
||||
"==" -> Opcode.BNZ
|
||||
"!=" -> Opcode.BZ
|
||||
"<" -> Opcode.BGEZS
|
||||
">" -> Opcode.BLEZS
|
||||
"<=" -> Opcode.BGZS
|
||||
">=" -> Opcode.BLZS
|
||||
"==" -> Opcode.BNE
|
||||
"!=" -> Opcode.BEQ
|
||||
"<" -> Opcode.BGES
|
||||
">" -> Opcode.BLES
|
||||
"<=" -> Opcode.BGTS
|
||||
">=" -> Opcode.BLTS
|
||||
else -> throw AssemblyError("weird operator")
|
||||
}
|
||||
} else {
|
||||
@ -1128,12 +1120,12 @@ class IRCodeGen(
|
||||
compResultReg = tr.resultReg
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
elseBranch = when (condition.operator) {
|
||||
"==" -> Opcode.BNZ
|
||||
"!=" -> Opcode.BZ
|
||||
"<" -> if (signed) Opcode.BGEZS else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
||||
">" -> if (signed) Opcode.BLEZS else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
|
||||
"<=" -> if (signed) Opcode.BGZS else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
|
||||
">=" -> if (signed) Opcode.BLZS else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
|
||||
"==" -> Opcode.BNE
|
||||
"!=" -> Opcode.BEQ
|
||||
"<" -> if (signed) Opcode.BGES else throw AssemblyError("unsigned < 0 shouldn't occur in codegen")
|
||||
">" -> if (signed) Opcode.BLES else throw AssemblyError("unsigned > 0 shouldn't occur in codegen")
|
||||
"<=" -> if (signed) Opcode.BGTS else throw AssemblyError("unsigned <= 0 shouldn't occur in codegen")
|
||||
">=" -> if (signed) Opcode.BLTS else throw AssemblyError("unsigned >= 0 shouldn't occur in codegen")
|
||||
else -> throw AssemblyError("weird operator")
|
||||
}
|
||||
}
|
||||
@ -1141,14 +1133,14 @@ class IRCodeGen(
|
||||
if(ifElse.elseScope.children.isEmpty()) {
|
||||
// just if
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(result, IRInstruction(elseBranch, branchDt, reg1=compResultReg, labelSymbol = afterIfLabel), null)
|
||||
addInstr(result, IRInstruction(elseBranch, branchDt, reg1=compResultReg, immediate = 0, labelSymbol = afterIfLabel), null)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
} else {
|
||||
// if and else
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(result, IRInstruction(elseBranch, branchDt, reg1=compResultReg, labelSymbol = elseLabel), null)
|
||||
addInstr(result, IRInstruction(elseBranch, branchDt, reg1=compResultReg, immediate = 0, labelSymbol = elseLabel), null)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||
@ -1172,14 +1164,14 @@ class IRCodeGen(
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(result, IRInstruction(Opcode.BZ, irDtLeft, reg1=tr.resultReg, labelSymbol = elseLabel), null)
|
||||
addInstr(result, IRInstruction(Opcode.BEQ, irDtLeft, reg1=tr.resultReg, immediate = 0, labelSymbol = elseLabel), null)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
} else {
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(result, IRInstruction(Opcode.BZ, irDtLeft, reg1=tr.resultReg, labelSymbol = afterIfLabel), null)
|
||||
addInstr(result, IRInstruction(Opcode.BEQ, irDtLeft, reg1=tr.resultReg, immediate = 0, labelSymbol = afterIfLabel), null)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
}
|
||||
@ -1203,12 +1195,12 @@ class IRCodeGen(
|
||||
null
|
||||
)
|
||||
val elseBranch = when (condition.operator) {
|
||||
"==" -> Opcode.BNZ
|
||||
"!=" -> Opcode.BZ
|
||||
"<" -> Opcode.BGEZS
|
||||
">" -> Opcode.BLEZS
|
||||
"<=" -> Opcode.BGZS
|
||||
">=" -> Opcode.BLZS
|
||||
"==" -> Opcode.BNE
|
||||
"!=" -> Opcode.BEQ
|
||||
"<" -> Opcode.BGES
|
||||
">" -> Opcode.BLES
|
||||
"<=" -> Opcode.BGTS
|
||||
">=" -> Opcode.BLTS
|
||||
else -> throw AssemblyError("weird operator")
|
||||
}
|
||||
if (ifElse.elseScope.children.isNotEmpty()) {
|
||||
@ -1240,81 +1232,116 @@ class IRCodeGen(
|
||||
branchDt = irDtLeft
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
when (condition.operator) {
|
||||
"==" -> {
|
||||
elseBranchOpcode = Opcode.BNE
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
val number = (condition.right as? PtNumber)?.number?.toInt()
|
||||
if (number!=null) {
|
||||
val elseBranchOpcode = when (condition.operator) {
|
||||
"==" -> Opcode.BNE
|
||||
"!=" -> Opcode.BEQ
|
||||
"<" -> if(signed) Opcode.BGES else Opcode.BGE
|
||||
">" -> if(signed) Opcode.BLES else Opcode.BLE
|
||||
"<=" -> if(signed) Opcode.BGTS else Opcode.BGT
|
||||
">=" -> if(signed) Opcode.BLTS else Opcode.BLT
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
|
||||
"!=" -> {
|
||||
elseBranchOpcode = Opcode.BEQ
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
if (ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result, IRInstruction(
|
||||
elseBranchOpcode, branchDt,
|
||||
reg1 = leftTr.resultReg, immediate = number,
|
||||
labelSymbol = elseLabel
|
||||
), null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result, IRInstruction(
|
||||
elseBranchOpcode, branchDt,
|
||||
reg1 = leftTr.resultReg, immediate = number,
|
||||
labelSymbol = afterIfLabel
|
||||
), null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
}
|
||||
|
||||
"<" -> {
|
||||
// else part when left >= right
|
||||
elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
}
|
||||
|
||||
">" -> {
|
||||
// else part when left <= right --> right >= left
|
||||
elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE
|
||||
elseBranchFirstReg = rightTr.resultReg
|
||||
elseBranchSecondReg = leftTr.resultReg
|
||||
}
|
||||
|
||||
"<=" -> {
|
||||
// else part when left > right
|
||||
elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
}
|
||||
|
||||
">=" -> {
|
||||
// else part when left < right --> right > left
|
||||
elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT
|
||||
elseBranchFirstReg = rightTr.resultReg
|
||||
elseBranchSecondReg = leftTr.resultReg
|
||||
}
|
||||
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
if (ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result, IRInstruction(
|
||||
elseBranchOpcode, branchDt,
|
||||
reg1 = elseBranchFirstReg, reg2 = elseBranchSecondReg,
|
||||
labelSymbol = elseLabel
|
||||
), null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result, IRInstruction(
|
||||
elseBranchOpcode, branchDt,
|
||||
reg1 = elseBranchFirstReg, reg2 = elseBranchSecondReg,
|
||||
labelSymbol = afterIfLabel
|
||||
), null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
val rightTr = expressionEval.translateExpression(condition.right)
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
when (condition.operator) {
|
||||
"==" -> {
|
||||
elseBranchOpcode = Opcode.BNER
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
}
|
||||
"!=" -> {
|
||||
elseBranchOpcode = Opcode.BEQR
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
}
|
||||
"<" -> {
|
||||
// else part when left >= right
|
||||
elseBranchOpcode = if (signed) Opcode.BGESR else Opcode.BGER
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
}
|
||||
">" -> {
|
||||
// else part when left <= right --> right >= left
|
||||
elseBranchOpcode = if (signed) Opcode.BGESR else Opcode.BGER
|
||||
elseBranchFirstReg = rightTr.resultReg
|
||||
elseBranchSecondReg = leftTr.resultReg
|
||||
}
|
||||
"<=" -> {
|
||||
// else part when left > right
|
||||
elseBranchOpcode = if (signed) Opcode.BGTSR else Opcode.BGTR
|
||||
elseBranchFirstReg = leftTr.resultReg
|
||||
elseBranchSecondReg = rightTr.resultReg
|
||||
}
|
||||
|
||||
">=" -> {
|
||||
// else part when left < right --> right > left
|
||||
elseBranchOpcode = if (signed) Opcode.BGTSR else Opcode.BGTR
|
||||
elseBranchFirstReg = rightTr.resultReg
|
||||
elseBranchSecondReg = leftTr.resultReg
|
||||
}
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
if (ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result, IRInstruction(
|
||||
elseBranchOpcode, branchDt,
|
||||
reg1 = elseBranchFirstReg, reg2 = elseBranchSecondReg,
|
||||
labelSymbol = elseLabel
|
||||
), null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
|
||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result, IRInstruction(
|
||||
elseBranchOpcode, branchDt,
|
||||
reg1 = elseBranchFirstReg, reg2 = elseBranchSecondReg,
|
||||
labelSymbol = afterIfLabel
|
||||
), null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@ -1393,11 +1420,11 @@ class IRCodeGen(
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val countTr = expressionEval.translateExpression(repeat.count)
|
||||
addToResult(result, countTr, countTr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.BZ, irDt, reg1=countTr.resultReg, labelSymbol = skipRepeatLabel), null)
|
||||
addInstr(result, IRInstruction(Opcode.BEQ, irDt, reg1=countTr.resultReg, immediate = 0, labelSymbol = skipRepeatLabel), null)
|
||||
result += labelFirstChunk(translateNode(repeat.statements), repeatLabel)
|
||||
val chunk = IRCodeChunk(null, null)
|
||||
chunk += IRInstruction(Opcode.DEC, irDt, reg1=countTr.resultReg)
|
||||
chunk += IRInstruction(Opcode.BNZ, irDt, reg1=countTr.resultReg, labelSymbol = repeatLabel)
|
||||
chunk += IRInstruction(Opcode.BNE, irDt, reg1=countTr.resultReg, immediate = 0, labelSymbol = repeatLabel)
|
||||
result += chunk
|
||||
result += IRCodeChunk(skipRepeatLabel, null)
|
||||
return result
|
||||
|
@ -258,8 +258,9 @@ fun parseMainModule(filepath: Path,
|
||||
for(lib in compTarget.machine.importLibs(compilerOptions, compTarget.name))
|
||||
importer.importImplicitLibraryModule(lib)
|
||||
|
||||
// always import prog8_lib and math
|
||||
importer.importImplicitLibraryModule("math")
|
||||
if(compilerOptions.compTarget.name!=VMTarget.NAME && !compilerOptions.experimentalCodegen) {
|
||||
importer.importImplicitLibraryModule("math")
|
||||
}
|
||||
importer.importImplicitLibraryModule("prog8_lib")
|
||||
|
||||
if (compilerOptions.launcher == CbmPrgLauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
||||
|
@ -211,10 +211,16 @@ main {
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, false, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
var result = compileText(target, true, src, writeAssembly = true)!!
|
||||
var virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||
vm.stepCount shouldBe 49
|
||||
vm.stepCount shouldBe 37
|
||||
}
|
||||
|
||||
result = compileText(target, false, src, writeAssembly = true)!!
|
||||
virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||
vm.stepCount shouldBe 48
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ TODO
|
||||
For next minor release
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
fix compiler crash on test/arithmethic/builtins.p8 and test the others as well
|
||||
|
||||
remove unused variables from IR output, such as sys.wait.jiffies when never calling sys.wait
|
||||
...
|
||||
|
||||
|
||||
|
@ -1,15 +1,34 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
sub calc(ubyte x, ubyte y) -> uword {
|
||||
repeat x+y {
|
||||
x++
|
||||
sub start() {
|
||||
cx16.r1=0
|
||||
for cx16.r0 in 0 to 10 {
|
||||
cx16.r1++
|
||||
}
|
||||
return x as uword * y
|
||||
}
|
||||
sub start() {
|
||||
txt.print_uw(calc(22, 33))
|
||||
txt.print_uw(cx16.r1)
|
||||
}
|
||||
}
|
||||
|
||||
;main33 {
|
||||
;
|
||||
; sub calc(ubyte x, ubyte y) -> uword {
|
||||
; %ir {{
|
||||
; loadcpu.b r42,A
|
||||
; loadcpu.w r42,XY
|
||||
; }}
|
||||
; repeat x+y {
|
||||
; x++
|
||||
; }
|
||||
; when x {
|
||||
; 1 -> y++
|
||||
; 3 -> y++
|
||||
; else -> y++
|
||||
; }
|
||||
; y--
|
||||
; return x as uword * y
|
||||
; }
|
||||
; sub start() {
|
||||
; txt.print_uw(calc(22, 33))
|
||||
; }
|
||||
;}
|
||||
|
@ -69,19 +69,23 @@ bstneg address - branch to location if Status bit Negat
|
||||
bstpos address - branch to location if Status bit Negative is not set
|
||||
bstvc address - branch to location if Status bit Overflow is not set
|
||||
bstvs address - branch to location if Status bit Overflow is not set
|
||||
bz reg1, address - branch to location if reg1 is zero
|
||||
bnz reg1, address - branch to location if reg1 is not zero
|
||||
bgzs reg1, address - branch to location if reg1 > 0 (signed)
|
||||
bgezs reg1, address - branch to location if reg1 >= 0 (signed)
|
||||
blzs reg1, address - branch to location if reg1 < 0 (signed)
|
||||
blezs reg1, address - branch to location if reg1 <= 0 (signed)
|
||||
beq reg1, reg2, address - jump to location in program given by location, if reg1 == reg2
|
||||
bne reg1, reg2, address - jump to location in program given by location, if reg1 != reg2
|
||||
bgt reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (unsigned)
|
||||
bgts reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (signed)
|
||||
bge reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (unsigned)
|
||||
bges reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (signed)
|
||||
( NOTE: there are no blt/ble instructions because these are equivalent to bgt/bge with the operands swapped around.)
|
||||
beqr reg1, reg2, address - jump to location in program given by location, if reg1 == reg2
|
||||
beq reg1, value, address - jump to location in program given by location, if reg1 == immediate value
|
||||
bner reg1, reg2, address - jump to location in program given by location, if reg1 != reg2
|
||||
bne reg1, value, address - jump to location in program given by location, if reg1 != immediate value
|
||||
bgtr reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (unsigned)
|
||||
bgt reg1, value, address - jump to location in program given by location, if reg1 > immediate value (unsigned)
|
||||
blt reg1, value, address - jump to location in program given by location, if reg1 < immediate value (unsigned)
|
||||
bgtsr reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (signed)
|
||||
bgts reg1, value, address - jump to location in program given by location, if reg1 > immediate value (signed)
|
||||
blts reg1, value, address - jump to location in program given by location, if reg1 < immediate value (signed)
|
||||
bger reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (unsigned)
|
||||
bge reg1, value, address - jump to location in program given by location, if reg1 >= immediate value (unsigned)
|
||||
ble reg1, value, address - jump to location in program given by location, if reg1 <= immediate value (unsigned)
|
||||
bgesr reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (signed)
|
||||
bges reg1, value, address - jump to location in program given by location, if reg1 >= immediate value (signed)
|
||||
bles reg1, value, address - jump to location in program given by location, if reg1 <= immediate value (signed)
|
||||
( 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, otherwise set reg1=0
|
||||
snz reg1, reg2 - set reg1=1 if reg2!=0, otherwise set reg1=0
|
||||
seq reg1, reg2 - set reg1=1 if reg1 == reg2, otherwise set reg1=0
|
||||
@ -244,18 +248,22 @@ enum class Opcode {
|
||||
BSTPOS,
|
||||
BSTVC,
|
||||
BSTVS,
|
||||
BZ,
|
||||
BNZ,
|
||||
BGZS,
|
||||
BGEZS,
|
||||
BLZS,
|
||||
BLEZS,
|
||||
BEQR,
|
||||
BEQ,
|
||||
BNER,
|
||||
BNE,
|
||||
BGTR,
|
||||
BGT,
|
||||
BLT,
|
||||
BGTSR,
|
||||
BGTS,
|
||||
BLTS,
|
||||
BGER,
|
||||
BGE,
|
||||
BLE,
|
||||
BGESR,
|
||||
BGES,
|
||||
BLES,
|
||||
SZ,
|
||||
SNZ,
|
||||
SEQ,
|
||||
@ -386,18 +394,22 @@ val OpcodesThatBranch = setOf(
|
||||
Opcode.BSTPOS,
|
||||
Opcode.BSTVC,
|
||||
Opcode.BSTVS,
|
||||
Opcode.BZ,
|
||||
Opcode.BNZ,
|
||||
Opcode.BGZS,
|
||||
Opcode.BGEZS,
|
||||
Opcode.BLZS,
|
||||
Opcode.BLEZS,
|
||||
Opcode.BEQR,
|
||||
Opcode.BEQ,
|
||||
Opcode.BNER,
|
||||
Opcode.BNE,
|
||||
Opcode.BGTR,
|
||||
Opcode.BGT,
|
||||
Opcode.BLT,
|
||||
Opcode.BGTSR,
|
||||
Opcode.BGTS,
|
||||
Opcode.BLTS,
|
||||
Opcode.BGER,
|
||||
Opcode.BGE,
|
||||
Opcode.BGES
|
||||
Opcode.BLE,
|
||||
Opcode.BGESR,
|
||||
Opcode.BGES,
|
||||
Opcode.BLES
|
||||
)
|
||||
|
||||
val OpcodesForCpuRegisters = setOf(
|
||||
@ -516,18 +528,22 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.BSTPOS to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTVC to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTVS to InstructionFormat.from("N,<a"),
|
||||
Opcode.BZ to InstructionFormat.from("BW,<r1,<a"),
|
||||
Opcode.BNZ to InstructionFormat.from("BW,<r1,<a"),
|
||||
Opcode.BGZS to InstructionFormat.from("BW,<r1,<a"),
|
||||
Opcode.BGEZS to InstructionFormat.from("BW,<r1,<a"),
|
||||
Opcode.BLZS to InstructionFormat.from("BW,<r1,<a"),
|
||||
Opcode.BLEZS to InstructionFormat.from("BW,<r1,<a"),
|
||||
Opcode.BEQ to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BNE to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGT to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGTS to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGE to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGES to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BEQR to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BEQ to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BNER to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BNE to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BGTR to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGT to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BLT to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BGTSR to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGTS to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BLTS to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BGER to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGE to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BLE to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
Opcode.BGESR to InstructionFormat.from("BW,<r1,<r2,<a"),
|
||||
Opcode.BGES to InstructionFormat.from("BW,<r1,<i,<a"),
|
||||
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"),
|
||||
@ -694,15 +710,14 @@ data class IRInstruction(
|
||||
IRDataType.FLOAT, null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
reg1direction = format.reg1
|
||||
reg2direction = format.reg2
|
||||
fpReg1direction = format.fpReg1
|
||||
fpReg2direction = format.fpReg2
|
||||
|
||||
if(opcode in setOf(Opcode.BEQ, Opcode.BNE,
|
||||
Opcode.BGT, Opcode.BGTS,
|
||||
Opcode.BGE, Opcode.BGES,
|
||||
if(opcode in setOf(Opcode.BEQR, Opcode.BNER,
|
||||
Opcode.BGTR, Opcode.BGTSR,
|
||||
Opcode.BGER, Opcode.BGESR,
|
||||
Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS,
|
||||
Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES,
|
||||
Opcode.SGE, Opcode.SGES)) {
|
||||
|
@ -5,52 +5,46 @@ import prog8.code.core.DataType
|
||||
import prog8.code.core.InternalCompilerException
|
||||
|
||||
|
||||
fun getTypeString(dt : DataType): String {
|
||||
return when(dt) {
|
||||
DataType.UBYTE -> "ubyte"
|
||||
DataType.BYTE -> "byte"
|
||||
DataType.UWORD -> "uword"
|
||||
DataType.WORD -> "word"
|
||||
DataType.FLOAT -> "float"
|
||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[]"
|
||||
DataType.ARRAY_B -> "byte[]"
|
||||
DataType.ARRAY_UW -> "uword[]"
|
||||
DataType.ARRAY_W -> "word[]"
|
||||
DataType.ARRAY_F -> "float[]"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
fun getTypeString(dt : DataType): String = when(dt) {
|
||||
DataType.UBYTE -> "ubyte"
|
||||
DataType.BYTE -> "byte"
|
||||
DataType.UWORD -> "uword"
|
||||
DataType.WORD -> "word"
|
||||
DataType.FLOAT -> "float"
|
||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[]"
|
||||
DataType.ARRAY_B -> "byte[]"
|
||||
DataType.ARRAY_UW -> "uword[]"
|
||||
DataType.ARRAY_W -> "word[]"
|
||||
DataType.ARRAY_F -> "float[]"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
|
||||
fun getTypeString(memvar: StMemVar): String {
|
||||
return when(memvar.dt) {
|
||||
DataType.UBYTE -> "ubyte"
|
||||
DataType.BYTE -> "byte"
|
||||
DataType.UWORD -> "uword"
|
||||
DataType.WORD -> "word"
|
||||
DataType.FLOAT -> "float"
|
||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]"
|
||||
DataType.ARRAY_B -> "byte[${memvar.length}]"
|
||||
DataType.ARRAY_UW -> "uword[${memvar.length}]"
|
||||
DataType.ARRAY_W -> "word[${memvar.length}]"
|
||||
DataType.ARRAY_F -> "float[${memvar.length}]"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
fun getTypeString(memvar: StMemVar): String = when(memvar.dt) {
|
||||
DataType.UBYTE -> "ubyte"
|
||||
DataType.BYTE -> "byte"
|
||||
DataType.UWORD -> "uword"
|
||||
DataType.WORD -> "word"
|
||||
DataType.FLOAT -> "float"
|
||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]"
|
||||
DataType.ARRAY_B -> "byte[${memvar.length}]"
|
||||
DataType.ARRAY_UW -> "uword[${memvar.length}]"
|
||||
DataType.ARRAY_W -> "word[${memvar.length}]"
|
||||
DataType.ARRAY_F -> "float[${memvar.length}]"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
|
||||
fun getTypeString(variable : StStaticVariable): String {
|
||||
return when(variable.dt) {
|
||||
DataType.UBYTE -> "ubyte"
|
||||
DataType.BYTE -> "byte"
|
||||
DataType.UWORD -> "uword"
|
||||
DataType.WORD -> "word"
|
||||
DataType.FLOAT -> "float"
|
||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]"
|
||||
DataType.ARRAY_B -> "byte[${variable.length}]"
|
||||
DataType.ARRAY_UW -> "uword[${variable.length}]"
|
||||
DataType.ARRAY_W -> "word[${variable.length}]"
|
||||
DataType.ARRAY_F -> "float[${variable.length}]"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
fun getTypeString(variable : StStaticVariable): String = when(variable.dt) {
|
||||
DataType.UBYTE -> "ubyte"
|
||||
DataType.BYTE -> "byte"
|
||||
DataType.UWORD -> "uword"
|
||||
DataType.WORD -> "word"
|
||||
DataType.FLOAT -> "float"
|
||||
DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]"
|
||||
DataType.ARRAY_B -> "byte[${variable.length}]"
|
||||
DataType.ARRAY_UW -> "uword[${variable.length}]"
|
||||
DataType.ARRAY_W -> "word[${variable.length}]"
|
||||
DataType.ARRAY_F -> "float[${variable.length}]"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
|
||||
fun convertIRType(typestr: String): IRDataType? {
|
||||
@ -101,134 +95,120 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, placeholder
|
||||
}
|
||||
var type: IRDataType? = convertIRType(typestr)
|
||||
val formats = instructionFormats.getValue(opcode)
|
||||
val format: InstructionFormat
|
||||
if(type !in formats) {
|
||||
type = IRDataType.BYTE
|
||||
format = if(type !in formats)
|
||||
formats.getValue(null)
|
||||
else
|
||||
val format: InstructionFormat =
|
||||
if(type !in formats) {
|
||||
type = IRDataType.BYTE
|
||||
if(type !in formats)
|
||||
formats.getValue(null)
|
||||
else
|
||||
formats.getValue(type)
|
||||
} else {
|
||||
formats.getValue(type)
|
||||
} else {
|
||||
format = formats.getValue(type)
|
||||
}
|
||||
}
|
||||
|
||||
// parse the operands
|
||||
val operands = rest.lowercase().split(",").toMutableList()
|
||||
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 fpReg3: Int? = null
|
||||
var value: Float? = null
|
||||
var operand: String?
|
||||
var immediateInt: Int? = null
|
||||
var immediateFp: Float? = null
|
||||
var address: Int? = null
|
||||
var labelSymbol: String? = null
|
||||
|
||||
fun parseValueOrPlaceholder(operand: String, location: Pair<IRCodeChunk, Int>?, rest: String, restIndex: Int): Float? {
|
||||
fun parseValueOrPlaceholder(operand: String, location: Pair<IRCodeChunk, Int>?): Float? {
|
||||
return if(operand[0].isLetter()) {
|
||||
labelSymbol = rest.split(",")[restIndex].trim()
|
||||
if(location!=null)
|
||||
placeholders[location] = labelSymbol!!
|
||||
placeholders[location] = operand
|
||||
null
|
||||
} else {
|
||||
parseIRValue(operand)
|
||||
}
|
||||
}
|
||||
|
||||
if(operands.isNotEmpty() && operands[0].isNotEmpty()) {
|
||||
operand = operands.removeFirst().trim()
|
||||
if(operand[0]=='r')
|
||||
reg1 = operand.substring(1).toInt()
|
||||
else if(operand[0]=='f' && operand[1]=='r')
|
||||
fpReg1 = operand.substring(2).toInt()
|
||||
else {
|
||||
value = parseValueOrPlaceholder(operand, location, rest, 0)
|
||||
operands.clear()
|
||||
}
|
||||
if(operands.isNotEmpty()) {
|
||||
operand = operands.removeFirst().trim()
|
||||
if(operand[0]=='r')
|
||||
reg2 = operand.substring(1).toInt()
|
||||
else if(operand[0]=='f' && operand[1]=='r')
|
||||
fpReg2 = operand.substring(2).toInt()
|
||||
else {
|
||||
value = parseValueOrPlaceholder(operand, location, rest, 1)
|
||||
operands.clear()
|
||||
}
|
||||
if(operands.isNotEmpty()) {
|
||||
operand = operands.removeFirst().trim()
|
||||
if(operand[0]=='r')
|
||||
reg3 = operand.substring(1).toInt()
|
||||
else if(operand[0]=='f' && operand[1]=='r')
|
||||
fpReg3 = operand.substring(2).toInt()
|
||||
else {
|
||||
value = parseValueOrPlaceholder(operand, location, rest, 2)
|
||||
operands.clear()
|
||||
}
|
||||
if(operands.isNotEmpty()) {
|
||||
throw IRParseException("unexpected even more operands? $operands rest=$rest'")
|
||||
operands.forEach { oper ->
|
||||
if(oper[0] == '&')
|
||||
throw IRParseException("address-of should be done with normal LOAD <symbol>")
|
||||
else if(oper[0] in "rR") {
|
||||
if(reg1==null) reg1 = oper.substring(1).toInt()
|
||||
else if(reg2==null) reg2 = 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()
|
||||
else if(fpReg2==null) fpReg2 = oper.substring(2).toInt()
|
||||
else throw IRParseException("too many fp register operands")
|
||||
} else if (oper[0].isDigit() || oper[0] == '$' || oper[0]=='%' || oper[0]=='-' || oper.startsWith("0x")) {
|
||||
val value = parseIRValue(oper)
|
||||
if(format.immediate) {
|
||||
if(immediateInt==null && immediateFp==null) {
|
||||
if (type == IRDataType.FLOAT)
|
||||
immediateFp = value
|
||||
else
|
||||
immediateInt = value.toInt()
|
||||
} else {
|
||||
address = value.toInt()
|
||||
}
|
||||
} else {
|
||||
address = value.toInt()
|
||||
}
|
||||
} else {
|
||||
if(!oper[0].isLetter())
|
||||
throw IRParseException("expected symbol name: $oper")
|
||||
labelSymbol = oper
|
||||
val value = parseValueOrPlaceholder(oper, location)
|
||||
if(value!=null)
|
||||
address = value.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
// shift the operands back into place
|
||||
while(reg1==null && reg2!=null) {
|
||||
reg1 = reg2
|
||||
reg2 = reg3
|
||||
reg3 = null
|
||||
}
|
||||
while(fpReg1==null && fpReg2!=null) {
|
||||
fpReg1 = fpReg2
|
||||
fpReg2 = fpReg3
|
||||
fpReg3 = null
|
||||
}
|
||||
if(reg3!=null)
|
||||
throw IRParseException("too many reg arguments $line")
|
||||
if(fpReg3!=null)
|
||||
throw IRParseException("too many fpreg arguments $line")
|
||||
|
||||
if(type!=null && type !in formats)
|
||||
throw IRParseException("invalid type code for $line")
|
||||
if(format.reg1!=OperandDirection.UNUSED && reg1==null)
|
||||
throw IRParseException("needs reg1 for $line")
|
||||
if(format.reg2!=OperandDirection.UNUSED && reg2==null)
|
||||
throw IRParseException("needs reg2 for $line")
|
||||
if(format.address!=OperandDirection.UNUSED && value==null && labelSymbol==null)
|
||||
throw IRParseException("needs value or symbol for $line")
|
||||
if(format.fpReg1!=OperandDirection.UNUSED && fpReg1==null)
|
||||
throw IRParseException("needs fpReg1 for $line")
|
||||
if(format.fpReg2!=OperandDirection.UNUSED && fpReg2==null)
|
||||
throw IRParseException("needs fpReg2 for $line")
|
||||
if(format.address!=OperandDirection.UNUSED && address==null && labelSymbol==null)
|
||||
throw IRParseException("needs address or symbol for $line")
|
||||
if(format.reg1==OperandDirection.UNUSED && reg1!=null)
|
||||
throw IRParseException("invalid reg1 for $line")
|
||||
if(format.reg2==OperandDirection.UNUSED && reg2!=null)
|
||||
throw IRParseException("invalid reg2 for $line")
|
||||
if(value!=null && format.immediate) {
|
||||
if(format.fpReg1==OperandDirection.UNUSED && fpReg1!=null)
|
||||
throw IRParseException("invalid fpReg1 for $line")
|
||||
if(format.fpReg2==OperandDirection.UNUSED && fpReg2!=null)
|
||||
throw IRParseException("invalid fpReg2 for $line")
|
||||
if(format.immediate) {
|
||||
if(immediateInt==null && immediateFp==null && labelSymbol==null)
|
||||
throw IRParseException("needs value or symbol for $line")
|
||||
when (type) {
|
||||
IRDataType.BYTE -> {
|
||||
if (value < -128 || value > 255)
|
||||
throw IRParseException("immediate value out of range for byte: $value")
|
||||
if (immediateInt!=null && (immediateInt!! < -128 || immediateInt!! > 255))
|
||||
throw IRParseException("immediate value out of range for byte: $immediateInt")
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if (value < -32768 || value > 65535)
|
||||
throw IRParseException("immediate value out of range for word: $value")
|
||||
if (immediateInt!=null && (immediateInt!! < -32768 || immediateInt!! > 65535))
|
||||
throw IRParseException("immediate value out of range for word: $immediateInt")
|
||||
}
|
||||
IRDataType.FLOAT -> {}
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
var immediateFp: Float? = null
|
||||
var immediateInt: Int? = null
|
||||
var address: Int? = null
|
||||
|
||||
if(format.address!=OperandDirection.UNUSED && value!=null)
|
||||
address = value.toInt()
|
||||
if(format.immediate && value!=null) {
|
||||
if(type==IRDataType.FLOAT)
|
||||
immediateFp = value
|
||||
else
|
||||
immediateInt = value.toInt()
|
||||
if(format.address!=OperandDirection.UNUSED && address==null && labelSymbol==null)
|
||||
throw IRParseException("requires address or symbol for $line")
|
||||
|
||||
if(labelSymbol!=null) {
|
||||
if (labelSymbol!![0] == 'r' && labelSymbol!![1].isDigit())
|
||||
throw IRParseException("labelsymbol confused with register?: $labelSymbol")
|
||||
}
|
||||
|
||||
if(opcode in OpcodesForCpuRegisters) {
|
||||
val reg = rest.split(',').last().lowercase().trim()
|
||||
val reg = operands.last().lowercase()
|
||||
if(reg !in setOf(
|
||||
"a", "x", "y",
|
||||
"ax", "ay", "xy",
|
||||
|
@ -23,33 +23,33 @@ class TestInstructions: FunSpec({
|
||||
}
|
||||
|
||||
test("with value") {
|
||||
val ins = IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42, address = 99)
|
||||
ins.opcode shouldBe Opcode.BZ
|
||||
val ins = IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1=42, immediate = 0, address = 99)
|
||||
ins.opcode shouldBe Opcode.BEQ
|
||||
ins.type shouldBe IRDataType.BYTE
|
||||
ins.reg1direction shouldBe OperandDirection.READ
|
||||
ins.fpReg1direction shouldBe OperandDirection.UNUSED
|
||||
ins.reg1 shouldBe 42
|
||||
ins.reg2 shouldBe null
|
||||
ins.address shouldBe 99
|
||||
ins.immediate shouldBe null
|
||||
ins.immediate shouldBe 0
|
||||
ins.immediateFp shouldBe null
|
||||
ins.labelSymbol shouldBe null
|
||||
ins.toString() shouldBe "bz.b r42,$63"
|
||||
ins.toString() shouldBe "beq.b r42,0,$63"
|
||||
}
|
||||
|
||||
test("with label") {
|
||||
val ins = IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=11, labelSymbol = "a.b.c")
|
||||
ins.opcode shouldBe Opcode.BZ
|
||||
val ins = IRInstruction(Opcode.BEQ, IRDataType.WORD, reg1=11, immediate = 0, labelSymbol = "a.b.c")
|
||||
ins.opcode shouldBe Opcode.BEQ
|
||||
ins.type shouldBe IRDataType.WORD
|
||||
ins.reg1direction shouldBe OperandDirection.READ
|
||||
ins.fpReg1direction shouldBe OperandDirection.UNUSED
|
||||
ins.reg1 shouldBe 11
|
||||
ins.reg2 shouldBe null
|
||||
ins.address shouldBe null
|
||||
ins.immediate shouldBe null
|
||||
ins.immediate shouldBe 0
|
||||
ins.immediateFp shouldBe null
|
||||
ins.labelSymbol shouldBe "a.b.c"
|
||||
ins.toString() shouldBe "bz.w r11,a.b.c"
|
||||
ins.toString() shouldBe "beq.w r11,0,a.b.c"
|
||||
}
|
||||
|
||||
test("with output registers") {
|
||||
@ -106,19 +106,19 @@ class TestInstructions: FunSpec({
|
||||
|
||||
test("missing type should fail") {
|
||||
shouldThrow<IllegalArgumentException> {
|
||||
IRInstruction(Opcode.BZ, reg1=42, address=99)
|
||||
IRInstruction(Opcode.BEQ, reg1=42, address=99)
|
||||
}
|
||||
}
|
||||
|
||||
test("missing registers should fail") {
|
||||
shouldThrowWithMessage<IllegalArgumentException>("missing reg1") {
|
||||
IRInstruction(Opcode.BZ, IRDataType.BYTE, address=99)
|
||||
IRInstruction(Opcode.BEQ, IRDataType.BYTE, immediate = 0, address=99)
|
||||
}
|
||||
}
|
||||
|
||||
test("missing address should fail") {
|
||||
shouldThrowWithMessage<IllegalArgumentException>("missing an address or labelsymbol") {
|
||||
IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42)
|
||||
IRInstruction(Opcode.BEQ, IRDataType.BYTE, immediate = 0, reg1=42)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,18 +188,22 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
Opcode.BSTNEG -> InsBSTNEG(ins)
|
||||
Opcode.BSTPOS -> InsBSTPOS(ins)
|
||||
Opcode.BSTVC, Opcode.BSTVS -> TODO("overflow status flag not yet supported in VM (BSTVC,BSTVS)")
|
||||
Opcode.BZ -> InsBZ(ins)
|
||||
Opcode.BNZ -> InsBNZ(ins)
|
||||
Opcode.BGZS -> InsBGZS(ins)
|
||||
Opcode.BGEZS -> InsBGEZS(ins)
|
||||
Opcode.BLZS -> InsBLZS(ins)
|
||||
Opcode.BLEZS -> InsBLEZS(ins)
|
||||
Opcode.BEQR -> InsBEQR(ins)
|
||||
Opcode.BNER -> InsBNER(ins)
|
||||
Opcode.BGTR -> InsBGTR(ins)
|
||||
Opcode.BGTSR -> InsBGTSR(ins)
|
||||
Opcode.BGER -> InsBGER(ins)
|
||||
Opcode.BGESR -> InsBGESR(ins)
|
||||
Opcode.BEQ -> InsBEQ(ins)
|
||||
Opcode.BNE -> InsBNE(ins)
|
||||
Opcode.BGT -> InsBGTU(ins)
|
||||
Opcode.BGT -> InsBGT(ins)
|
||||
Opcode.BLT -> InsBLT(ins)
|
||||
Opcode.BGTS -> InsBGTS(ins)
|
||||
Opcode.BGE -> InsBGEU(ins)
|
||||
Opcode.BLTS -> InsBLTS(ins)
|
||||
Opcode.BGE -> InsBGE(ins)
|
||||
Opcode.BLE -> InsBLE(ins)
|
||||
Opcode.BGES -> InsBGES(ins)
|
||||
Opcode.BLES -> InsBLES(ins)
|
||||
Opcode.SZ -> InsSZ(ins)
|
||||
Opcode.SNZ -> InsSNZ(ins)
|
||||
Opcode.SEQ -> InsSEQ(ins)
|
||||
@ -697,115 +701,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBZ(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
if(registers.getUB(i.reg1!!)==0.toUByte())
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if(registers.getUW(i.reg1!!)==0.toUShort())
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsBNZ(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
if(registers.getUB(i.reg1!!)!=0.toUByte())
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if(registers.getUW(i.reg1!!)!=0.toUShort())
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsBGZS(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
if(registers.getSB(i.reg1!!)>0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if(registers.getSW(i.reg1!!)>0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsBGEZS(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
if(registers.getSB(i.reg1!!)>=0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if(registers.getSW(i.reg1!!)>=0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsBLZS(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
if(registers.getSB(i.reg1!!)<0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if(registers.getSW(i.reg1!!)<0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsBLEZS(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
if(registers.getSB(i.reg1!!)<=0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if(registers.getSW(i.reg1!!)<=0)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsBEQ(i: IRInstruction) {
|
||||
private fun InsBEQR(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperands(i)
|
||||
if(left==right)
|
||||
branchTo(i)
|
||||
@ -813,7 +709,15 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBNE(i: IRInstruction) {
|
||||
private fun InsBEQ(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsImmU(i)
|
||||
if(left==right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBNER(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperands(i)
|
||||
if(left!=right)
|
||||
branchTo(i)
|
||||
@ -821,40 +725,110 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGTU(i: IRInstruction) {
|
||||
private fun InsBNE(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsImmU(i)
|
||||
if(left!=right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGTR(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsU(i)
|
||||
if(left>right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGT(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsImmU(i)
|
||||
if(left>right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBLT(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsImmU(i)
|
||||
if(left<right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGTSR(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperands(i)
|
||||
if(left>right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGTS(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperands(i)
|
||||
val (left: Int, right: Int) = getBranchOperandsImm(i)
|
||||
if(left>right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGEU(i: IRInstruction) {
|
||||
private fun InsBLTS(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperandsImm(i)
|
||||
if(left<right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGER(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsU(i)
|
||||
if(left>=right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGE(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsImmU(i)
|
||||
if(left>=right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBLE(i: IRInstruction) {
|
||||
val (left: UInt, right: UInt) = getBranchOperandsImmU(i)
|
||||
if(left<=right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGESR(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperands(i)
|
||||
if(left>=right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBGES(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperands(i)
|
||||
val (left: Int, right: Int) = getBranchOperandsImm(i)
|
||||
if(left>=right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsBLES(i: IRInstruction) {
|
||||
val (left: Int, right: Int) = getBranchOperandsImm(i)
|
||||
if(left<=right)
|
||||
branchTo(i)
|
||||
else
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsSZ(i: IRInstruction) {
|
||||
val (_: Int, right: Int) = getSetOnConditionOperands(i)
|
||||
val value = if(right==0) 1 else 0
|
||||
@ -2228,6 +2202,17 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBranchOperandsImm(i: IRInstruction): Pair<Int, Int> {
|
||||
return when(i.type) {
|
||||
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), i.immediate!!)
|
||||
IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), i.immediate!!)
|
||||
IRDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBranchOperandsU(i: IRInstruction): Pair<UInt, UInt> {
|
||||
return when(i.type) {
|
||||
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt())
|
||||
@ -2239,6 +2224,17 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBranchOperandsImmU(i: IRInstruction): Pair<UInt, UInt> {
|
||||
return when(i.type) {
|
||||
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), i.immediate!!.toUInt())
|
||||
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), i.immediate!!.toUInt())
|
||||
IRDataType.FLOAT -> {
|
||||
throw IllegalArgumentException("can't use float here")
|
||||
}
|
||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLogicalOperandsU(i: IRInstruction): Pair<UInt, UInt> {
|
||||
return when(i.type) {
|
||||
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt())
|
||||
|
Loading…
Reference in New Issue
Block a user