mirror of
https://github.com/irmen/prog8.git
synced 2025-08-14 22:27:48 +00:00
IR: support for indirect jump after if
This commit is contained in:
@@ -880,12 +880,13 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump): MutableList<IRCodeChunkBase> {
|
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump): MutableList<IRCodeChunkBase> {
|
||||||
if(isIndirectJump(goto))
|
|
||||||
TODO("indirect jump after if ${ifElse.position}")
|
|
||||||
|
|
||||||
val condition = ifElse.condition as? PtBinaryExpression
|
val condition = ifElse.condition as? PtBinaryExpression
|
||||||
if(condition==null || condition.left.type!=DataType.FLOAT)
|
if(condition==null || condition.left.type!=DataType.FLOAT) {
|
||||||
return ifWithOnlyJump_IntegerCond(ifElse, goto)
|
return if(isIndirectJump(goto))
|
||||||
|
ifWithOnlyIndirectJump_IntegerCond(ifElse, goto)
|
||||||
|
else
|
||||||
|
ifWithOnlyNormalJump_IntegerCond(ifElse, goto)
|
||||||
|
}
|
||||||
|
|
||||||
// we assume only a binary expression can contain a floating point.
|
// we assume only a binary expression can contain a floating point.
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
@@ -893,6 +894,7 @@ class IRCodeGen(
|
|||||||
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
addToResult(result, leftTr, -1, leftTr.resultFpReg)
|
||||||
val rightTr = expressionEval.translateExpression(condition.right)
|
val rightTr = expressionEval.translateExpression(condition.right)
|
||||||
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
||||||
|
var afterIfLabel = ""
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
val compResultReg = registers.nextFree()
|
val compResultReg = registers.nextFree()
|
||||||
it += IRInstruction(
|
it += IRInstruction(
|
||||||
@@ -902,6 +904,33 @@ class IRCodeGen(
|
|||||||
fpReg1 = leftTr.resultFpReg,
|
fpReg1 = leftTr.resultFpReg,
|
||||||
fpReg2 = rightTr.resultFpReg
|
fpReg2 = rightTr.resultFpReg
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(isIndirectJump(goto)) {
|
||||||
|
// indirect jump to target so the if has to jump past it instead
|
||||||
|
afterIfLabel = createLabelName()
|
||||||
|
when(condition.operator) {
|
||||||
|
"==" -> {
|
||||||
|
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = compResultReg, immediate = 0)
|
||||||
|
it += IRInstruction(Opcode.BSTNE, labelSymbol = afterIfLabel)
|
||||||
|
}
|
||||||
|
"!=" -> {
|
||||||
|
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = compResultReg, immediate = 0)
|
||||||
|
it += IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val gotoOpcode = when (condition.operator) {
|
||||||
|
"<" -> Opcode.BGES
|
||||||
|
">" -> Opcode.BLES
|
||||||
|
"<=" -> Opcode.BGTS
|
||||||
|
">=" -> Opcode.BLTS
|
||||||
|
else -> throw AssemblyError("weird operator")
|
||||||
|
}
|
||||||
|
it += IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = afterIfLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it += IRInstruction(Opcode.JUMPI, labelSymbol = goto.identifier!!.name)
|
||||||
|
} else {
|
||||||
|
// normal jump, directly to target with branch opcode
|
||||||
when(condition.operator) {
|
when(condition.operator) {
|
||||||
"==" -> {
|
"==" -> {
|
||||||
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = compResultReg, immediate = 0)
|
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = compResultReg, immediate = 0)
|
||||||
@@ -926,6 +955,9 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if(afterIfLabel.isNotEmpty())
|
||||||
|
result += IRCodeChunk(afterIfLabel, null)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,7 +970,140 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ifWithOnlyJump_IntegerCond(ifElse: PtIfElse, goto: PtJump): MutableList<IRCodeChunkBase> {
|
private fun ifWithOnlyIndirectJump_IntegerCond(ifElse: PtIfElse, goto: PtJump): MutableList<IRCodeChunkBase> {
|
||||||
|
// indirect jump to target so the if has to jump past it instead
|
||||||
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
val afterIfLabel = createLabelName()
|
||||||
|
val gotoSymbol = goto.identifier!!.name
|
||||||
|
|
||||||
|
fun ifNonZeroIntThenJump_BinExpr(condition: PtBinaryExpression) {
|
||||||
|
if(condition.operator in LogicalOperators) {
|
||||||
|
val trCond = expressionEval.translateExpression(condition)
|
||||||
|
result += trCond.chunks
|
||||||
|
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel), null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val leftTr = expressionEval.translateExpression(condition.left)
|
||||||
|
val irDt = leftTr.dt
|
||||||
|
val signed = condition.left.type in SignedDatatypes
|
||||||
|
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||||
|
val number = (condition.right as? PtNumber)?.number?.toInt()
|
||||||
|
if(number!=null) {
|
||||||
|
val firstReg = leftTr.resultReg
|
||||||
|
when(condition.operator) {
|
||||||
|
"==" -> {
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.CMPI, irDt, reg1 = firstReg, immediate = number)
|
||||||
|
it += IRInstruction(Opcode.BSTNE, labelSymbol = afterIfLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"!=" -> {
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.CMPI, irDt, reg1 = firstReg, immediate = number)
|
||||||
|
it += IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val opcode = when (condition.operator) {
|
||||||
|
"<" -> 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")
|
||||||
|
}
|
||||||
|
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, labelSymbol = afterIfLabel), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
val rightTr = expressionEval.translateExpression(condition.right)
|
||||||
|
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||||
|
val firstReg: Int
|
||||||
|
val secondReg: Int
|
||||||
|
val opcode: Opcode
|
||||||
|
var useCmp = false
|
||||||
|
when (condition.operator) {
|
||||||
|
"==" -> {
|
||||||
|
useCmp = true
|
||||||
|
opcode = Opcode.BSTNE
|
||||||
|
firstReg = leftTr.resultReg
|
||||||
|
secondReg = rightTr.resultReg
|
||||||
|
}
|
||||||
|
"!=" -> {
|
||||||
|
useCmp = true
|
||||||
|
opcode = Opcode.BSTEQ
|
||||||
|
firstReg = leftTr.resultReg
|
||||||
|
secondReg = rightTr.resultReg
|
||||||
|
}
|
||||||
|
"<" -> {
|
||||||
|
opcode = if (signed) Opcode.BGESR else Opcode.BGER
|
||||||
|
firstReg = leftTr.resultReg
|
||||||
|
secondReg = rightTr.resultReg
|
||||||
|
}
|
||||||
|
">" -> {
|
||||||
|
// swapped operands
|
||||||
|
opcode = if (signed) Opcode.BGESR else Opcode.BGER
|
||||||
|
firstReg = rightTr.resultReg
|
||||||
|
secondReg = leftTr.resultReg
|
||||||
|
}
|
||||||
|
"<=" -> {
|
||||||
|
opcode = if (signed) Opcode.BGTSR else Opcode.BGTR
|
||||||
|
firstReg = leftTr.resultReg
|
||||||
|
secondReg = rightTr.resultReg
|
||||||
|
}
|
||||||
|
">=" -> {
|
||||||
|
// swapped operands
|
||||||
|
opcode = if (signed) Opcode.BGTSR else Opcode.BGTR
|
||||||
|
firstReg = rightTr.resultReg
|
||||||
|
secondReg = leftTr.resultReg
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("invalid comparison operator")
|
||||||
|
}
|
||||||
|
|
||||||
|
if(useCmp) {
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
it += IRInstruction(Opcode.CMP, irDt, reg1 = firstReg, reg2 = secondReg)
|
||||||
|
it += IRInstruction(opcode, labelSymbol = afterIfLabel)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, labelSymbol = afterIfLabel), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when(val cond = ifElse.condition) {
|
||||||
|
is PtTypeCast -> {
|
||||||
|
require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes)
|
||||||
|
val tr = expressionEval.translateExpression(cond)
|
||||||
|
result += tr.chunks
|
||||||
|
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel), null)
|
||||||
|
}
|
||||||
|
is PtIdentifier, is PtArrayIndexer, is PtBuiltinFunctionCall, is PtFunctionCall, is PtContainmentCheck -> {
|
||||||
|
val tr = expressionEval.translateExpression(cond)
|
||||||
|
result += tr.chunks
|
||||||
|
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel), null)
|
||||||
|
}
|
||||||
|
is PtPrefix -> {
|
||||||
|
require(cond.operator=="not")
|
||||||
|
val tr = expressionEval.translateExpression(cond.value)
|
||||||
|
result += tr.chunks
|
||||||
|
addInstr(result, IRInstruction(Opcode.BSTNE, labelSymbol = afterIfLabel), null)
|
||||||
|
}
|
||||||
|
is PtBinaryExpression -> {
|
||||||
|
ifNonZeroIntThenJump_BinExpr(cond)
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird if condition ${ifElse.condition}")
|
||||||
|
}
|
||||||
|
|
||||||
|
addInstr(result, IRInstruction(Opcode.JUMPI, labelSymbol = gotoSymbol), null)
|
||||||
|
result += IRCodeChunk(afterIfLabel, null)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ifWithOnlyNormalJump_IntegerCond(ifElse: PtIfElse, goto: PtJump): MutableList<IRCodeChunkBase> {
|
||||||
|
// normal goto after if, using branch instructions
|
||||||
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
|
||||||
fun ifNonZeroIntThenJump_BinExpr(condition: PtBinaryExpression) {
|
fun ifNonZeroIntThenJump_BinExpr(condition: PtBinaryExpression) {
|
||||||
|
1917
examples/test.p8
1917
examples/test.p8
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user