From a587482edf18f8bb23b6da7aab1284d148115952 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 18 Jun 2023 13:34:56 +0200 Subject: [PATCH] optimize dangling else --- .../src/prog8/optimizer/Extensions.kt | 4 +- .../src/prog8/optimizer/StatementOptimizer.kt | 22 +++-- compiler/src/prog8/compiler/Compiler.kt | 2 +- docs/source/todo.rst | 2 - examples/test.p8 | 90 +++++++------------ 5 files changed, 51 insertions(+), 69 deletions(-) diff --git a/codeOptimizers/src/prog8/optimizer/Extensions.kt b/codeOptimizers/src/prog8/optimizer/Extensions.kt index cb76ffa30..b79394d01 100644 --- a/codeOptimizers/src/prog8/optimizer/Extensions.kt +++ b/codeOptimizers/src/prog8/optimizer/Extensions.kt @@ -43,9 +43,9 @@ fun Program.constantFold(errors: IErrorReporter, compTarget: ICompilationTarget) fun Program.optimizeStatements(errors: IErrorReporter, functions: IBuiltinFunctions, - compTarget: ICompilationTarget + options: CompilationOptions ): Int { - val optimizer = StatementOptimizer(this, errors, functions, compTarget) + val optimizer = StatementOptimizer(this, errors, functions, options) optimizer.visit(this) val optimizationCount = optimizer.applyModifications() diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index a07424672..4d9dd7193 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -13,7 +13,7 @@ import kotlin.math.floor class StatementOptimizer(private val program: Program, private val errors: IErrorReporter, private val functions: IBuiltinFunctions, - private val compTarget: ICompilationTarget + private val options: CompilationOptions ) : AstWalker() { override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { @@ -39,7 +39,7 @@ class StatementOptimizer(private val program: Program, if(string!=null) { val pos = functionCallStatement.position if (string.value.length == 1) { - val firstCharEncoded = compTarget.encodeString(string.value, string.encoding)[0] + val firstCharEncoded = options.compTarget.encodeString(string.value, string.encoding)[0] val chrout = FunctionCallStatement( IdentifierReference(listOf("txt", "chrout"), pos), mutableListOf(NumericLiteral(DataType.UBYTE, firstCharEncoded.toDouble(), pos)), @@ -51,7 +51,7 @@ class StatementOptimizer(private val program: Program, IAstModification.Remove(stringDecl, stringDecl.parent as IStatementContainer) ) } else if (string.value.length == 2) { - val firstTwoCharsEncoded = compTarget.encodeString(string.value.take(2), string.encoding) + val firstTwoCharsEncoded = options.compTarget.encodeString(string.value.take(2), string.encoding) val chrout1 = FunctionCallStatement( IdentifierReference(listOf("txt", "chrout"), pos), mutableListOf(NumericLiteral(DataType.UBYTE, firstTwoCharsEncoded[0].toDouble(), pos)), @@ -108,6 +108,16 @@ class StatementOptimizer(private val program: Program, } } + // remove obvious dangling elses (else after a return) + if(ifElse.elsepart.isNotEmpty() && ifElse.truepart.statements.singleOrNull() is Return) { + val elsePart = AnonymousScope(ifElse.elsepart.statements, ifElse.elsepart.position) + if(options.slowCodegenWarnings) + errors.warn("else can be omitted", ifElse.elsepart.position) + return listOf( + IAstModification.ReplaceNode(ifElse.elsepart, AnonymousScope(mutableListOf(), ifElse.elsepart.position), ifElse), + IAstModification.InsertAfter(ifElse, elsePart, parent as IStatementContainer) + ) + } return noModifications } @@ -141,7 +151,7 @@ class StatementOptimizer(private val program: Program, val size = sv.value.length if(size==1) { // loop over string of length 1 -> just assign the single character - val character = compTarget.encodeString(sv.value, sv.encoding)[0] + val character = options.compTarget.encodeString(sv.value, sv.encoding)[0] val byte = NumericLiteral(DataType.UBYTE, character.toDouble(), iterable.position) val scope = AnonymousScope(mutableListOf(), forLoop.position) scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, forLoop.position), byte, AssignmentOrigin.OPTIMIZER, forLoop.position)) @@ -326,7 +336,7 @@ class StatementOptimizer(private val program: Program, if (rightCv == 0.0) { return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { - if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..3.0 && compTarget.name!=VMTarget.NAME) { + if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..3.0 && options.compTarget.name!=VMTarget.NAME) { // replace by several INCs if it's not a memory address (inc on a memory mapped register doesn't work very well) val incs = AnonymousScope(mutableListOf(), assignment.position) repeat(rightCv.toInt()) { @@ -340,7 +350,7 @@ class StatementOptimizer(private val program: Program, if (rightCv == 0.0) { return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { - if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..3.0 && compTarget.name!=VMTarget.NAME) { + if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..3.0 && options.compTarget.name!=VMTarget.NAME) { // replace by several DECs if it's not a memory address (dec on a memory mapped register doesn't work very well) val decs = AnonymousScope(mutableListOf(), assignment.position) repeat(rightCv.toInt()) { diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index d875f64ac..c1507bf2d 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -371,7 +371,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e // keep optimizing expressions and statements until no more steps remain val optsDone1 = program.simplifyExpressions(errors, compTarget) val optsDone2 = program.splitBinaryExpressions(compilerOptions) - val optsDone3 = program.optimizeStatements(errors, functions, compTarget) + val optsDone3 = program.optimizeStatements(errors, functions, compilerOptions) val optsDone4 = program.inlineSubroutines() program.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away errors.report() diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 6bf8a0eb4..7e04dc0cf 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,6 @@ TODO ==== -- optimize a "dangling else" - ... diff --git a/examples/test.p8 b/examples/test.p8 index 3b04995c9..ba7dbbbd1 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,67 +1,41 @@ -%import math %import textio %zeropage basicsafe -main { - - const ubyte WIDTH=255 - const ubyte HEIGHT=240 +main { sub start() { - sys.gfx_enable(0) ; enable lo res screen - ;; gfx2.screen_mode(4) - repeat { + txt.print_ub(danglingelse(32)) + txt.spc() + txt.print_ub(danglingelse(99)) + txt.spc() + txt.print_ub(danglingelse(1)) + txt.spc() + txt.print_ub(danglingelse(100)) + txt.nl() + txt.print_ub(danglingelse2(32)) + txt.spc() + txt.print_ub(danglingelse2(99)) + txt.spc() + txt.print_ub(danglingelse2(1)) + txt.spc() + txt.print_ub(danglingelse2(100)) + txt.nl() + } - ubyte xx - ubyte yy + sub danglingelse(ubyte bb) -> ubyte { + if bb==32 + return 32 + else if bb==99 + return 99 + else + return 0 + } - for yy in 0 to HEIGHT-1 { - for xx in 0 to WIDTH-1 { - ubyte value = math.direction(WIDTH/2, HEIGHT/2, xx, yy) - ;; gfx2.plot(xx,yy,value) - sys.gfx_plot(xx, yy, value*10) - } - } - } + sub danglingelse2(ubyte bb) -> ubyte { + if bb==32 + return 32 + if bb==99 + return 99 + return 0 } } - - -;main { -; -; sub start() { -; -; const ubyte HEIGHT = txt.DEFAULT_HEIGHT -; const ubyte WIDTH = txt.DEFAULT_WIDTH -; const ubyte HALFWIDTH = txt.DEFAULT_WIDTH/2 -; const ubyte HALFHEIGHT = txt.DEFAULT_HEIGHT/2 -; -; ubyte @zp value -; ubyte xx -; ubyte yy -;; for yy in 0 to HEIGHT-1 { -;; for xx in 0 to WIDTH-1 { -;; value = math.atan(HALFWIDTH, HALFHEIGHT, xx, yy) -;; txt.setchr(xx,yy,value) -;; } -;; } -;; -;; byte sx -;; byte sy -;; for sy in -HEIGHT/2 to HEIGHT/2 { -;; for sx in -WIDTH/2 to WIDTH/2 { -;; value = math.direction_sc(0, 0, sx, sy) -;; txt.setchr(sx+WIDTH/2 as ubyte,sy+HEIGHT/2 as ubyte,value) -;; } -;; } -; -; for yy in 0 to HEIGHT-1 { -; for xx in 0 to WIDTH-1 { -; value = math.direction(HALFWIDTH, HALFHEIGHT, xx, yy) -; txt.setchr(xx,yy,value) -; } -; } -; -; goto start -; } -;}