From c15c10a94e0457b1e9b5ad53801f5efe94dd0ac3 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 5 Sep 2023 00:53:58 +0200 Subject: [PATCH] fixed 'unroll CONSTANTEXPR' compiler errors --- .../optimizer/ConstantFoldingOptimizer.kt | 1 - .../src/prog8/optimizer/StatementOptimizer.kt | 3 ++- .../compiler/astprocessing/AstChecker.kt | 21 ++++++++++++------- .../astprocessing/IntermediateAstMaker.kt | 2 +- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 2 +- .../src/prog8/ast/statements/AstStatements.kt | 7 +++++-- compilerAst/src/prog8/ast/walk/AstWalker.kt | 1 + docs/source/todo.rst | 3 --- examples/test.p8 | 21 +++++++------------ parser/antlr/Prog8ANTLR.g4 | 2 +- 10 files changed, 31 insertions(+), 32 deletions(-) diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index b4a36aa8c..2473a7af3 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -628,5 +628,4 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() { return null } } - } diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index 6ca42b7a4..a8a467386 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -384,7 +384,8 @@ class StatementOptimizer(private val program: Program, } override fun before(unrollLoop: UnrollLoop, parent: Node): Iterable { - return if(unrollLoop.iterations<1) + val iterations = unrollLoop.iterations.constValue(program)?.number?.toInt() + return if(iterations!=null && iterations<1) listOf(IAstModification.Remove(unrollLoop, parent as IStatementContainer)) else noModifications diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 64f02e0eb..ff7d2773d 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -76,14 +76,19 @@ internal class AstChecker(private val program: Program, } override fun visit(unrollLoop: UnrollLoop) { - if(unrollLoop.iterations<0 || unrollLoop.iterations>65535) - errors.err("invalid number of unrolls", unrollLoop.position) - unrollLoop.body.statements.forEach { - if(it !is InlineAssembly && it !is Assignment && it !is BuiltinFunctionCallStatement && it !is FunctionCallStatement && it !is PostIncrDecr) - errors.err("invalid statement in unroll loop", it.position) - } - if(unrollLoop.iterations * unrollLoop.body.statements.size > 256) { - errors.warn("large number of unrolls, potential code size issue", unrollLoop.position) + val iterations = unrollLoop.iterations.constValue(program)?.number?.toInt() + if(iterations==null) { + errors.err("unroll needs constant number of iterations", unrollLoop.position) + } else { + if (iterations < 0 || iterations > 65535) + errors.err("invalid number of unrolls", unrollLoop.position) + unrollLoop.body.statements.forEach { + if (it !is InlineAssembly && it !is Assignment && it !is BuiltinFunctionCallStatement && it !is FunctionCallStatement && it !is PostIncrDecr) + errors.err("invalid statement in unroll loop", it.position) + } + if (iterations * unrollLoop.body.statements.size > 256) { + errors.warn("large number of unrolls, potential code size issue", unrollLoop.position) + } } super.visit(unrollLoop) } diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index 8f178f948..5ad6a55b1 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -326,7 +326,7 @@ class IntermediateAstMaker(private val program: Program) { private fun transform(srcUnroll: UnrollLoop): PtNodeGroup { val result = PtNodeGroup() - repeat(srcUnroll.iterations) { + repeat(srcUnroll.iterations.constValue(program)!!.number.toInt()) { srcUnroll.body.statements.forEach { result.add(transformStatement(it)) } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 73150ba81..4c3e5529e 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -583,7 +583,7 @@ private fun Prog8ANTLRParser.RepeatloopContext.toAst(): RepeatLoop { } private fun Prog8ANTLRParser.UnrollloopContext.toAst(): UnrollLoop { - val iterations = integerliteral().toAst().number.toInt() + val iterations = expression().toAst() val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst()) val scope = AnonymousScope(statements, statement_block()?.toPosition() ?: statement().toPosition()) diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 898d5d164..54df69a45 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -931,11 +931,13 @@ class RepeatLoop(var iterations: Expression?, var body: AnonymousScope, override iterations?.referencesIdentifier(nameInSource)==true || body.referencesIdentifier(nameInSource) } -class UnrollLoop(val iterations: Int, var body: AnonymousScope, override val position: Position) : Statement() { +class UnrollLoop(var iterations: Expression, var body: AnonymousScope, override val position: Position) : Statement() { + // note: the iterations needs to evaluate to a constant number once parsed. override lateinit var parent: Node override fun linkParents(parent: Node) { this.parent = parent + iterations.linkParents(this) body.linkParents(this) } @@ -943,13 +945,14 @@ class UnrollLoop(val iterations: Int, var body: AnonymousScope, override val pos override fun replaceChildNode(node: Node, replacement: Node) { if (node===body) body = replacement as AnonymousScope + else if (node===iterations) iterations = replacement as Expression else throw FatalAstException("invalid replace") replacement.parent = this } override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - override fun referencesIdentifier(nameInSource: List): Boolean = body.referencesIdentifier(nameInSource) + override fun referencesIdentifier(nameInSource: List): Boolean = iterations.referencesIdentifier(nameInSource) || body.referencesIdentifier(nameInSource) } class UntilLoop(var body: AnonymousScope, diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index 99d031c57..0226ad958 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -398,6 +398,7 @@ abstract class AstWalker { fun visit(unrollLoop: UnrollLoop, parent: Node) { track(before(unrollLoop, parent), unrollLoop, parent) + unrollLoop.iterations.accept(this, unrollLoop) unrollLoop.body.accept(this, unrollLoop) track(after(unrollLoop, parent), unrollLoop, parent) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 69eb18a93..94458fa1a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,9 +1,6 @@ TODO ==== -- fix compiler crash on "unroll for x in 0 to txt.DEFAULT_WIDTH-1" -- fix compiler error on "unroll txt.DEFAULT_WIDTH" - - prefix prog8 subroutines with p8s_ instead of p8_ to not let them clash with variables in the asm?? - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction diff --git a/examples/test.p8 b/examples/test.p8 index 5b198b599..210ef4a57 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,22 +1,15 @@ %import textio -%zeropage basicsafe +%zeropage dontuse main { sub start() { + const ubyte CONSTANT=80 + cx16.r0 = 0 + unroll CONSTANT-10 { + cx16.r0++ + } + txt.print_uw(cx16.r0) - ubyte[5] xx = [11,22,33,44,55] - ubyte[5] yy = [101,102,103,104,105] - ubyte i=3 - ubyte j = 4 - uword screen - - ubyte result = xx[i] + yy[j] - txt.print_ub(result) ; 149 - txt.nl() - result = xx[i] + yy[i] - txt.print_ub(result) ; 148 - txt.nl() - @(screen+i) = xx[i] + yy[i] ; ubyte index = 100 ; ubyte[] t_index = [1,2,3,4,5] diff --git a/parser/antlr/Prog8ANTLR.g4 b/parser/antlr/Prog8ANTLR.g4 index d268be591..cdbfaba25 100644 --- a/parser/antlr/Prog8ANTLR.g4 +++ b/parser/antlr/Prog8ANTLR.g4 @@ -299,7 +299,7 @@ untilloop: 'do' (statement | statement_block) EOL? 'until' expression ; repeatloop: 'repeat' expression? EOL? (statement | statement_block) ; -unrollloop: 'unroll' integerliteral? EOL? (statement | statement_block) ; +unrollloop: 'unroll' expression EOL? (statement | statement_block) ; // note: expression must evaluate to a constant whenstmt: 'when' expression EOL? '{' EOL? (when_choice | EOL) * '}' EOL? ;