IR: fix up missing indirect goto codegen

This commit is contained in:
Irmen de Jong 2024-12-24 18:54:26 +01:00
parent 49959af752
commit e174b31344
2 changed files with 73 additions and 37 deletions

View File

@ -284,31 +284,23 @@ class IRCodeGen(
val address = goto.target.asConstInteger()
val label = (goto.target as? PtIdentifier)?.name
if(address!=null) {
val branchIns = when(branch.condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, address = address)
BranchCondition.CC -> IRInstruction(Opcode.BSTCC, address = address)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTEQ, address = address)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTNE, address = address)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTNEG, address = address)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTPOS, address = address)
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, address = address)
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, address = address)
}
val branchIns = IRBranchInstr(branch.condition, address=address)
addInstr(result, branchIns, null)
} else if(label!=null && !isIndirectJump(goto)) {
val branchIns = when(branch.condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label)
BranchCondition.CC -> IRInstruction(Opcode.BSTCC, labelSymbol = label)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTEQ, labelSymbol = label)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTNE, labelSymbol = label)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTNEG, labelSymbol = label)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTPOS, labelSymbol = label)
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, labelSymbol = label)
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = label)
}
val branchIns = IRBranchInstr(branch.condition, label = label)
addInstr(result, branchIns, null)
} else {
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
val skipJumpLabel = createLabelName()
// note that the branch opcode used is the opposite as the branch condition, because it needs to skip the indirect jump
val branchIns = IRInvertedBranchInstr(branch.condition, label = skipJumpLabel)
// evaluate jump address expression into a register and jump indirectly to it
addInstr(result, branchIns, null)
val tr = expressionEval.translateExpression(goto.target)
result += tr.chunks
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.JUMPI, reg1=tr.resultReg)
}
result += IRCodeChunk(skipJumpLabel, null)
}
if(branch.falseScope.children.isNotEmpty())
result += translateNode(branch.falseScope)
@ -317,16 +309,7 @@ class IRCodeGen(
val elseLabel = createLabelName()
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
val branchIns = when(branch.condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
BranchCondition.CC -> IRInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
BranchCondition.VC -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel)
BranchCondition.VS -> IRInstruction(Opcode.BSTVC, labelSymbol = elseLabel)
}
val branchIns = IRInvertedBranchInstr(branch.condition, label = elseLabel)
addInstr(result, branchIns, null)
result += translateNode(branch.trueScope)
if(branch.falseScope.children.isNotEmpty()) {
@ -341,6 +324,60 @@ class IRCodeGen(
return result
}
private fun IRBranchInstr(condition: BranchCondition, label: String?=null, address: Int?=null): IRInstruction {
if(label!=null)
return when(condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label)
BranchCondition.CC -> IRInstruction(Opcode.BSTCC, labelSymbol = label)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTEQ, labelSymbol = label)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTNE, labelSymbol = label)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTNEG, labelSymbol = label)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTPOS, labelSymbol = label)
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, labelSymbol = label)
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = label)
}
else if(address!=null) {
return when(condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, address = address)
BranchCondition.CC -> IRInstruction(Opcode.BSTCC, address = address)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTEQ, address = address)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTNE, address = address)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTNEG, address = address)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTPOS, address = address)
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, address = address)
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, address = address)
}
}
else throw AssemblyError("need label or address for branch")
}
private fun IRInvertedBranchInstr(condition: BranchCondition, label: String?=null, address: Int?=null): IRInstruction {
if(label!=null)
return when(condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCC, labelSymbol = label)
BranchCondition.CC -> IRInstruction(Opcode.BSTCS, labelSymbol = label)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTNE, labelSymbol = label)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTEQ, labelSymbol = label)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTPOS, labelSymbol = label)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTNEG, labelSymbol = label)
BranchCondition.VC -> IRInstruction(Opcode.BSTVS, labelSymbol = label)
BranchCondition.VS -> IRInstruction(Opcode.BSTVC, labelSymbol = label)
}
else if(address!=null) {
return when(condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCC, address = address)
BranchCondition.CC -> IRInstruction(Opcode.BSTCS, address = address)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTNE, address = address)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTEQ, address = address)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTPOS, address = address)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTNEG, address = address)
BranchCondition.VC -> IRInstruction(Opcode.BSTVS, address = address)
BranchCondition.VS -> IRInstruction(Opcode.BSTVC, address = address)
}
}
else throw AssemblyError("need label or address for branch")
}
private fun labelFirstChunk(chunks: IRCodeChunks, label: String): IRCodeChunks {
if(chunks.isEmpty()) {
return listOf(
@ -990,6 +1027,7 @@ class IRCodeGen(
ifWithOnlyNormalJump_IntegerCond(ifElse, goto)
}
// floating-point condition only from here!
// we assume only a binary expression can contain a floating point.
val result = mutableListOf<IRCodeChunkBase>()
val leftTr = expressionEval.translateExpression(condition.left)
@ -1060,7 +1098,7 @@ class IRCodeGen(
else if(goto.target is PtIdentifier && !isIndirectJump(goto))
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = (goto.target as PtIdentifier).name)
else
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
throw AssemblyError("non-indirect jump shouldn't have an expression as target")
}
}
}
@ -1079,7 +1117,7 @@ class IRCodeGen(
if(identifier!=null && !isIndirectJump(goto))
IRInstruction(branchOpcode, labelSymbol = identifier.name)
else
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
TODO("JUMP to expression address ${goto.target}")
}
}
@ -1128,7 +1166,6 @@ class IRCodeGen(
}
}
} else {
val rightTr = expressionEval.translateExpression(condition.right)
addToResult(result, rightTr, rightTr.resultReg, -1)
val firstReg: Int
@ -1258,7 +1295,7 @@ class IRCodeGen(
else if(goto.target is PtIdentifier && !isIndirectJump(goto))
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, labelSymbol = (goto.target as PtIdentifier).name), null)
else
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
throw AssemblyError("non-indirect jump shouldn't have an expression as target")
}
}
} else {
@ -1317,7 +1354,7 @@ class IRCodeGen(
else if(goto.target is PtIdentifier && !isIndirectJump(goto))
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, labelSymbol = (goto.target as PtIdentifier).name), null)
else
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
throw AssemblyError("non-indirect jump shouldn't have an expression as target")
}
}
}

View File

@ -60,7 +60,6 @@ IR/VM
- implement missing operators in AssignmentGen (array shifts etc)
- fix call() return value handling
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
- make it possible to jump and branch to a computed address (expression) in all cases, see TODO("JUMP to expression address"
- idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
global initialization values are simply a list of LOAD instructions.
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.