optimize: flip if true/else blocks if the else block only contains a jump (inverting the condition)

This commit is contained in:
Irmen de Jong 2023-12-13 21:54:19 +01:00
parent 01c2112881
commit 58400f53bc
5 changed files with 42 additions and 79 deletions

View File

@ -110,6 +110,22 @@ class StatementOptimizer(private val program: Program,
IAstModification.InsertAfter(ifElse, elsePart, parent as IStatementContainer)
)
}
// switch if/else around if the else is just a jump or branch
if(ifElse.elsepart.isNotEmpty() && ifElse.elsepart.statements.size==1) {
val jump = ifElse.elsepart.statements[0]
if(jump is Jump) {
val newTruePart = AnonymousScope(mutableListOf(jump), ifElse.elsepart.position)
val newElsePart = AnonymousScope(ifElse.truepart.statements, ifElse.truepart.position)
val invertedCondition = PrefixExpression("not", ifElse.condition, ifElse.condition.position)
return listOf(
IAstModification.ReplaceNode(ifElse.elsepart, newElsePart, ifElse),
IAstModification.ReplaceNode(ifElse.truepart, newTruePart, ifElse),
IAstModification.ReplaceNode(ifElse.condition, invertedCondition, ifElse)
)
}
}
return noModifications
}
@ -460,7 +476,7 @@ class StatementOptimizer(private val program: Program,
if(whenStmt.condition.inferType(program).isBool) {
if(whenStmt.choices.all { it.values?.size==1 }) {
if (whenStmt.choices.all { it.values!!.single().constValue(program)!!.number in arrayOf(0.0, 1.0) }) {
// it's a when statement on booleans that can just be replaced by an if or if..else.
// it's a when statement on booleans that can just be replaced by an if or if-else.
if (whenStmt.choices.size == 1) {
return if(whenStmt.choices[0].values!![0].constValue(program)!!.number==1.0) {
replaceWithIf(whenStmt.condition, whenStmt.choices[0].statements, null)

View File

@ -112,9 +112,11 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
program.processAstBeforeAsmGeneration(compilationOptions, args.errors)
args.errors.report()
val intermediateAst = IntermediateAstMaker(program, args.errors).transform()
// println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************")
// printProgram(program)
val intermediateAst = IntermediateAstMaker(program, args.errors).transform()
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
// printAst(intermediateAst, true, ::println)

View File

@ -95,6 +95,16 @@ internal class BoolRemover(val program: Program) : AstWalker() {
}
return noModifications
}
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator=="not") {
val exprDt = expr.expression.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val nonBoolDt = if(exprDt==DataType.BOOL) DataType.UBYTE else exprDt
val equalZero = BinaryExpression(expr.expression, "==", NumericLiteral(nonBoolDt, 0.0, expr.expression.position), expr.expression.position)
return listOf(IAstModification.ReplaceNode(expr, equalZero, parent))
}
return noModifications
}
}
internal fun wrapWithBooleanCastIfNeeded(expr: Expression, program: Program): Expression? {

View File

@ -2,17 +2,15 @@
TODO
====
- optimize: flip if true/else blocks if the else block only contains a jump (invert condition!)
- IR (expericodegen): fix code for calling routines that return a boolean in a status register such as Carry flag, it has to store the flag value somewhere
- merge branch optimize-st for some optimizations regardign SymbolTable use
- merge branch optimize-st for some optimizations regarding SymbolTable use
- [on branch: call-pointers] allow calling a subroutine via a pointer variable (indirect JSR, optimized form of callfar())
modify programs (shell, paint) that now use callfar
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
- IR (expericodegen): fix code for calling routines that return a boolean in a status register such as Carry flag, it has to store the flag value somewhere
...

View File

@ -4,86 +4,23 @@
main {
sub start() {
; 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()
; exptected output: no2, no3, no5, yes6, no7, yes8
if not test_c_clear()
goto skip1
if test_c_set()
txt.print("yes1\n")
else
txt.print("no1\n")
goto skip1
txt.print("no1\n")
skip1:
if test_c_clear()
goto skip2
txt.print("yes2\n")
else
txt.print("no2\n")
goto skip2
txt.print("no1\n")
skip2:
if not test_c_set()
goto skip3
else
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_c_clear() {
cx16.r0++
}
do {
cx16.r0++
} until test_c_set()
txt.print("done\n")
}
asmsub test_c_clear() -> bool @Pc {