tweaking IR instruction set branch instructions

This commit is contained in:
Irmen de Jong 2023-04-09 21:08:35 +02:00
parent ccdf05e922
commit 9b952fbc44
11 changed files with 569 additions and 523 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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