mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
fixed silly if-goto expression code in IR codegen where it used too many branching instructions
This commit is contained in:
parent
27568c2bef
commit
def7e87151
@ -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) {
|
||||
|
@ -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'
|
||||
}
|
||||
|
||||
|
@ -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>
|
@ -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
|
||||
}
|
||||
})
|
@ -3,7 +3,6 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- if epxr goto somewhere creates inefficient code on virt
|
||||
- regression test the various projects before release
|
||||
|
||||
...
|
||||
|
Loading…
Reference in New Issue
Block a user