mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
optimize if-else handling of asmsub boolean result in status flags
This commit is contained in:
parent
0da9142009
commit
a546c2247d
@ -103,7 +103,7 @@ class PtIfElse(position: Position) : PtNode(position) {
|
||||
|
||||
class PtJump(val identifier: PtIdentifier?,
|
||||
val address: UInt?,
|
||||
val generatedLabel: String?,
|
||||
val generatedLabel: String?, // TODO remove this ? always uses identifier...
|
||||
position: Position) : PtNode(position) {
|
||||
init {
|
||||
identifier?.let {it.parent = this }
|
||||
|
@ -120,7 +120,7 @@ enum class BranchCondition {
|
||||
PL, // PL == POS
|
||||
POS,
|
||||
VS,
|
||||
VC,
|
||||
VC
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,14 +65,18 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
|
||||
}
|
||||
is PtJump -> {
|
||||
if(node.identifier!=null) {
|
||||
val stNode = st.lookup(node.identifier!!.name)!!
|
||||
val stNode = st.lookup(node.identifier!!.name)
|
||||
if(stNode==null)
|
||||
throw AssemblyError("name not found ${node.identifier}")
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
else if(node.generatedLabel!=null) {
|
||||
val stNode = st.lookup(node.generatedLabel!!)!!
|
||||
val stNode = st.lookup(node.generatedLabel!!)
|
||||
if(stNode==null)
|
||||
throw AssemblyError("name not found ${node.generatedLabel}")
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
|
@ -279,7 +279,98 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
return call
|
||||
}
|
||||
|
||||
private fun transform(srcIf: IfElse): PtIfElse {
|
||||
private fun transform(srcIf: IfElse): PtNode {
|
||||
|
||||
fun codeForStatusflag(fcall: FunctionCallExpression, flag: Statusflag, equalToZero: Boolean): PtNodeGroup? {
|
||||
// if the condition is a call to something that returns a boolean in a status register (C, Z, V, N),
|
||||
// a smarter branch is possible using a conditional branch node.
|
||||
val (branchTrue, branchFalse) = if(equalToZero) {
|
||||
when (flag) {
|
||||
Statusflag.Pc -> BranchCondition.CC to BranchCondition.CS
|
||||
Statusflag.Pz -> BranchCondition.NZ to BranchCondition.Z
|
||||
Statusflag.Pv -> BranchCondition.VC to BranchCondition.VS
|
||||
Statusflag.Pn -> BranchCondition.POS to BranchCondition.NEG
|
||||
}
|
||||
} else {
|
||||
when (flag) {
|
||||
Statusflag.Pc -> BranchCondition.CS to BranchCondition.CC
|
||||
Statusflag.Pz -> BranchCondition.Z to BranchCondition.NZ
|
||||
Statusflag.Pv -> BranchCondition.VS to BranchCondition.VC
|
||||
Statusflag.Pn -> BranchCondition.NEG to BranchCondition.POS
|
||||
}
|
||||
}
|
||||
val jump = srcIf.truepart.statements.firstOrNull() as? Jump
|
||||
if (jump!=null) {
|
||||
// only a jump, use a conditional branch to the jump target.
|
||||
val nodes = PtNodeGroup()
|
||||
nodes.add(transformExpression(fcall))
|
||||
val branch = PtConditionalBranch(branchTrue, srcIf.position)
|
||||
val ifScope = PtNodeGroup()
|
||||
ifScope.add(transform(jump))
|
||||
val elseScope = PtNodeGroup()
|
||||
if(srcIf.elsepart.isNotEmpty())
|
||||
throw FatalAstException("if-else with only a goto should no longer have statements in the else part")
|
||||
branch.add(ifScope)
|
||||
branch.add(elseScope)
|
||||
nodes.add(branch)
|
||||
return nodes
|
||||
} else {
|
||||
// skip over the true part if the condition is false
|
||||
val nodes = PtNodeGroup()
|
||||
nodes.add(transformExpression(fcall))
|
||||
val branch = PtConditionalBranch(branchFalse, srcIf.position)
|
||||
val ifScope = PtNodeGroup()
|
||||
val elseLabel = program.makeLabel("celse")
|
||||
val endLabel = program.makeLabel("cend")
|
||||
val scopedElseLabel = (srcIf.definingScope.scopedName + elseLabel).joinToString(".")
|
||||
val scopedEndLabel = (srcIf.definingScope.scopedName + endLabel).joinToString(".")
|
||||
val elseLbl = PtIdentifier(scopedElseLabel, DataType.UNDEFINED, srcIf.position)
|
||||
val endLbl = PtIdentifier(scopedEndLabel, DataType.UNDEFINED, srcIf.position)
|
||||
ifScope.add(PtJump(elseLbl, null, null, srcIf.position))
|
||||
val elseScope = PtNodeGroup()
|
||||
branch.add(ifScope)
|
||||
branch.add(elseScope)
|
||||
nodes.add(branch)
|
||||
for (stmt in srcIf.truepart.statements)
|
||||
nodes.add(transformStatement(stmt))
|
||||
if(srcIf.elsepart.isNotEmpty())
|
||||
nodes.add(PtJump(endLbl, null, null, srcIf.position))
|
||||
nodes.add(PtLabel(elseLabel, srcIf.position))
|
||||
if(srcIf.elsepart.isNotEmpty()) {
|
||||
for (stmt in srcIf.elsepart.statements)
|
||||
nodes.add(transformStatement(stmt))
|
||||
}
|
||||
if(srcIf.elsepart.isNotEmpty())
|
||||
nodes.add(PtLabel(endLabel, srcIf.position))
|
||||
return nodes
|
||||
}
|
||||
}
|
||||
|
||||
val binexpr = srcIf.condition as? BinaryExpression
|
||||
if(binexpr!=null && binexpr.right.constValue(program)?.number==0.0) {
|
||||
if(binexpr.operator=="==" || binexpr.operator=="!=") {
|
||||
val fcall = binexpr.left as? FunctionCallExpression
|
||||
if(fcall!=null) {
|
||||
val returnRegs = fcall.target.targetSubroutine(program)?.asmReturnvaluesRegisters
|
||||
if(returnRegs!=null && returnRegs.size==1 && returnRegs[0].statusflag!=null) {
|
||||
val translated = codeForStatusflag(fcall, returnRegs[0].statusflag!!, binexpr.operator == "==")
|
||||
if(translated!=null)
|
||||
return translated
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val fcall = srcIf.condition as? FunctionCallExpression
|
||||
if (fcall != null) {
|
||||
val returnRegs = fcall.target.targetSubroutine(program)?.asmReturnvaluesRegisters
|
||||
if(returnRegs!=null && returnRegs.size==1 && returnRegs[0].statusflag!=null) {
|
||||
val translated = codeForStatusflag(fcall, returnRegs[0].statusflag!!, false)
|
||||
if(translated!=null)
|
||||
return translated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ifelse = PtIfElse(srcIf.position)
|
||||
ifelse.add(transformExpression(srcIf.condition))
|
||||
val ifScope = PtNodeGroup()
|
||||
|
@ -2,7 +2,8 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- optimize if-else expressions whose condition returns the boolean status in a status register to use a branch opcode instead of a comparison against 0
|
||||
- optimize: flip if true/else blocks if the else block only contains a jump (invert condition!)
|
||||
- remove PtJump generatedLabel (always seems to use identifier)
|
||||
|
||||
- merge branch optimize-st for some optimizations regardign SymbolTable use
|
||||
|
||||
|
132
examples/test.p8
132
examples/test.p8
@ -4,39 +4,141 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
bool @shared blerp = test(100)
|
||||
; expected output: 0000
|
||||
cx16.r0L = test_c_clear()
|
||||
cx16.r1L = test_z_clear()
|
||||
cx16.r2L = test_n_clear()
|
||||
cx16.r3L = test_v_clear()
|
||||
txt.print_ub(cx16.r0L)
|
||||
txt.print_ub(cx16.r1L)
|
||||
txt.print_ub(cx16.r2L)
|
||||
txt.print_ub(cx16.r3L)
|
||||
txt.nl()
|
||||
; expected output: 1111
|
||||
cx16.r0L = test_c_set()
|
||||
cx16.r1L = test_z_set()
|
||||
cx16.r2L = test_n_set()
|
||||
cx16.r3L = test_v_set()
|
||||
txt.print_ub(cx16.r0L)
|
||||
txt.print_ub(cx16.r1L)
|
||||
txt.print_ub(cx16.r2L)
|
||||
txt.print_ub(cx16.r3L)
|
||||
txt.nl()
|
||||
|
||||
if test(100)
|
||||
goto skip
|
||||
txt.print("no0")
|
||||
; exptected output: no2, no3, no5, yes6, no7, yes8
|
||||
if not test_c_clear()
|
||||
goto skip1
|
||||
else
|
||||
txt.print("no1\n")
|
||||
|
||||
skip:
|
||||
if test(100) {
|
||||
txt.print("yes1")
|
||||
skip1:
|
||||
if test_c_clear()
|
||||
goto skip2
|
||||
}
|
||||
txt.print("no1")
|
||||
else
|
||||
txt.print("no2\n")
|
||||
|
||||
skip2:
|
||||
if test(100)
|
||||
txt.print("yes2")
|
||||
|
||||
if not test_c_set()
|
||||
goto skip3
|
||||
else
|
||||
txt.print("no2")
|
||||
txt.print("no3\n")
|
||||
|
||||
skip3:
|
||||
if test_c_set()
|
||||
goto skip4
|
||||
else
|
||||
txt.print("no4\n")
|
||||
|
||||
skip4:
|
||||
|
||||
if test_c_clear() {
|
||||
txt.print("yes5\n")
|
||||
goto skip5
|
||||
}
|
||||
txt.print("no5\n")
|
||||
|
||||
skip5:
|
||||
if not test_c_clear() {
|
||||
txt.print("yes6\n")
|
||||
goto skip6
|
||||
}
|
||||
txt.print("no6\n")
|
||||
|
||||
skip6:
|
||||
if test_c_clear()
|
||||
txt.print("yes7\n")
|
||||
else
|
||||
txt.print("no7\n")
|
||||
|
||||
if not test_c_clear()
|
||||
txt.print("yes8\n")
|
||||
else
|
||||
txt.print("no8\n")
|
||||
|
||||
|
||||
while test(100) {
|
||||
while test_c_clear() {
|
||||
cx16.r0++
|
||||
}
|
||||
|
||||
do {
|
||||
cx16.r0++
|
||||
} until test(100)
|
||||
} until test_c_set()
|
||||
}
|
||||
|
||||
asmsub test(ubyte value @A) -> bool @Pz {
|
||||
asmsub test_c_clear() -> bool @Pc {
|
||||
%asm {{
|
||||
clc
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_z_clear() -> bool @Pz {
|
||||
%asm {{
|
||||
lda #1
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_n_clear() -> bool @Pn {
|
||||
%asm {{
|
||||
lda #1
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_v_clear() -> bool @Pv {
|
||||
%asm {{
|
||||
clv
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_c_set() -> bool @Pc {
|
||||
%asm {{
|
||||
sec
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_z_set() -> bool @Pz {
|
||||
%asm {{
|
||||
lda #0
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_n_set() -> bool @Pn {
|
||||
%asm {{
|
||||
lda #-1
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_v_set() -> bool @Pv {
|
||||
%asm {{
|
||||
bit +
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user