mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +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 {
|
private fun translate(branch: PtConditionalBranch): IRCodeChunks {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
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()
|
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
|
// 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) {
|
val branchIns = when(branch.condition) {
|
||||||
@ -329,8 +364,8 @@ class IRCodeGen(
|
|||||||
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
||||||
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
||||||
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
||||||
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, labelSymbol = elseLabel)
|
BranchCondition.VC -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel)
|
||||||
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel)
|
BranchCondition.VS -> IRInstruction(Opcode.BSTVC, labelSymbol = elseLabel)
|
||||||
}
|
}
|
||||||
addInstr(result, branchIns, null)
|
addInstr(result, branchIns, null)
|
||||||
result += translateNode(branch.trueScope)
|
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 signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
||||||
val irDt = irType(ifElse.condition.left.type)
|
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 {
|
fun translateNonZeroComparison(): IRCodeChunks {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
val elseBranch = when(ifElse.condition.operator) {
|
val elseBranch = when(ifElse.condition.operator) {
|
||||||
|
@ -40,6 +40,7 @@ dependencies {
|
|||||||
implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.4'
|
implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.4'
|
||||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
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'
|
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="codeGenExperimental" />
|
||||||
<orderEntry type="module" module-name="codeGenIntermediate" />
|
<orderEntry type="module" module-name="codeGenIntermediate" />
|
||||||
<orderEntry type="module" module-name="virtualmachine" />
|
<orderEntry type="module" module-name="virtualmachine" />
|
||||||
|
<orderEntry type="module" module-name="intermediate" scope="TEST" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
@ -10,6 +10,9 @@ import prog8.ast.statements.Assignment
|
|||||||
import prog8.code.target.C64Target
|
import prog8.code.target.C64Target
|
||||||
import prog8.code.target.Cx16Target
|
import prog8.code.target.Cx16Target
|
||||||
import prog8.code.target.VMTarget
|
import prog8.code.target.VMTarget
|
||||||
|
import prog8.intermediate.IRFileReader
|
||||||
|
import prog8.intermediate.IRSubroutine
|
||||||
|
import prog8.intermediate.Opcode
|
||||||
import prog8.vm.VmRunner
|
import prog8.vm.VmRunner
|
||||||
import prog8tests.helpers.compileText
|
import prog8tests.helpers.compileText
|
||||||
import kotlin.io.path.readText
|
import kotlin.io.path.readText
|
||||||
@ -298,4 +301,30 @@ main {
|
|||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
compileText(target, false, src, writeAssembly = true) shouldNotBe null
|
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
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- if epxr goto somewhere creates inefficient code on virt
|
|
||||||
- regression test the various projects before release
|
- regression test the various projects before release
|
||||||
|
|
||||||
...
|
...
|
||||||
|
Loading…
Reference in New Issue
Block a user