fixed silly if-goto expression code in IR codegen where it used too many branching instructions

This commit is contained in:
Irmen de Jong 2022-12-12 22:47:15 +01:00
parent 27568c2bef
commit def7e87151
5 changed files with 94 additions and 3 deletions

View File

@ -320,6 +320,41 @@ class IRCodeGen(
private fun translate(branch: PtConditionalBranch): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val goto = branch.trueScope.children.firstOrNull() as? PtJump
if(goto is PtJump && branch.falseScope.children.isEmpty()) {
// special case the form: if_cc <condition> goto <place>
val address = goto.address?.toInt()
if(address!=null) {
val branchIns = when(branch.condition) {
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, value = address)
BranchCondition.CC -> IRInstruction(Opcode.BSTCC, value = address)
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTEQ, value = address)
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTNE, value = address)
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTNEG, value = address)
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTPOS, value = address)
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, value = address)
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, value = address)
}
addInstr(result, branchIns, null)
} else {
val label = if(goto.generatedLabel!=null) goto.generatedLabel else goto.identifier!!.targetName.joinToString(".")
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)
}
addInstr(result, branchIns, null)
}
return result
}
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) {
@ -329,8 +364,8 @@ class IRCodeGen(
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.BSTVC, labelSymbol = elseLabel)
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel)
BranchCondition.VC -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel)
BranchCondition.VS -> IRInstruction(Opcode.BSTVC, labelSymbol = elseLabel)
}
addInstr(result, branchIns, null)
result += translateNode(branch.trueScope)
@ -868,6 +903,32 @@ class IRCodeGen(
val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
val irDt = irType(ifElse.condition.left.type)
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
if(goto!=null && ifElse.elseScope.children.isEmpty()) {
// special case the form: if <condition> goto <place>
val result = mutableListOf<IRCodeChunkBase>()
val leftReg = registers.nextFree()
val rightReg = registers.nextFree()
result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
result += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1)
val opcode = when(ifElse.condition.operator) {
"==" -> Opcode.BEQ
"!=" -> Opcode.BNE
"<" -> Opcode.BLT
">" -> Opcode.BGT
"<=" -> Opcode.BLE
">=" -> Opcode.BGE
else -> throw AssemblyError("invalid comparison operator")
}
if(goto.address!=null)
addInstr(result, IRInstruction(opcode, irDt, reg1=leftReg, reg2=rightReg, value = goto.address?.toInt()), null)
else if(goto.generatedLabel!=null)
addInstr(result, IRInstruction(opcode, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = goto.generatedLabel), null)
else
addInstr(result, IRInstruction(opcode, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = goto.identifier!!.targetName.joinToString(".")), null)
return result
}
fun translateNonZeroComparison(): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>()
val elseBranch = when(ifElse.condition.operator) {

View File

@ -40,6 +40,7 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.4'
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
testImplementation project(':intermediate')
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.3.2'
}

View File

@ -23,5 +23,6 @@
<orderEntry type="module" module-name="codeGenExperimental" />
<orderEntry type="module" module-name="codeGenIntermediate" />
<orderEntry type="module" module-name="virtualmachine" />
<orderEntry type="module" module-name="intermediate" scope="TEST" />
</component>
</module>

View File

@ -10,6 +10,9 @@ import prog8.ast.statements.Assignment
import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
import prog8.intermediate.IRFileReader
import prog8.intermediate.IRSubroutine
import prog8.intermediate.Opcode
import prog8.vm.VmRunner
import prog8tests.helpers.compileText
import kotlin.io.path.readText
@ -298,4 +301,30 @@ main {
val target = VMTarget()
compileText(target, false, src, writeAssembly = true) shouldNotBe null
}
test("compile virtual: short code for if-goto") {
val src = """
main {
sub start() {
if_cc
goto ending
if_cs
goto ending
if cx16.r0 goto ending
if cx16.r0==0 goto ending
if cx16.r0!=0 goto ending
if cx16.r0s>0 goto ending
if cx16.r0s<0 goto ending
ending:
}
}"""
val result = compileText(VMTarget(), true, src, writeAssembly = true)!!
result.program.entrypoint.statements.size shouldBe 9
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
val irProgram = IRFileReader().read(virtfile)
val start = irProgram.blocks[0].children[0] as IRSubroutine
val instructions = start.chunks.flatMap { c->c.instructions }
instructions.size shouldBe 18
instructions.last().opcode shouldBe Opcode.RETURN
}
})

View File

@ -3,7 +3,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- if epxr goto somewhere creates inefficient code on virt
- regression test the various projects before release
...