fixed 'unroll CONSTANTEXPR' compiler errors

This commit is contained in:
Irmen de Jong 2023-09-05 00:53:58 +02:00
parent 9fca978725
commit c15c10a94e
10 changed files with 31 additions and 32 deletions

View File

@ -628,5 +628,4 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
return null return null
} }
} }
} }

View File

@ -384,7 +384,8 @@ class StatementOptimizer(private val program: Program,
} }
override fun before(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> { override fun before(unrollLoop: UnrollLoop, parent: Node): Iterable<IAstModification> {
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)) listOf(IAstModification.Remove(unrollLoop, parent as IStatementContainer))
else else
noModifications noModifications

View File

@ -76,14 +76,19 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(unrollLoop: UnrollLoop) { override fun visit(unrollLoop: UnrollLoop) {
if(unrollLoop.iterations<0 || unrollLoop.iterations>65535) val iterations = unrollLoop.iterations.constValue(program)?.number?.toInt()
errors.err("invalid number of unrolls", unrollLoop.position) if(iterations==null) {
unrollLoop.body.statements.forEach { errors.err("unroll needs constant number of iterations", unrollLoop.position)
if(it !is InlineAssembly && it !is Assignment && it !is BuiltinFunctionCallStatement && it !is FunctionCallStatement && it !is PostIncrDecr) } else {
errors.err("invalid statement in unroll loop", it.position) if (iterations < 0 || iterations > 65535)
} errors.err("invalid number of unrolls", unrollLoop.position)
if(unrollLoop.iterations * unrollLoop.body.statements.size > 256) { unrollLoop.body.statements.forEach {
errors.warn("large number of unrolls, potential code size issue", unrollLoop.position) 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) super.visit(unrollLoop)
} }

View File

@ -326,7 +326,7 @@ class IntermediateAstMaker(private val program: Program) {
private fun transform(srcUnroll: UnrollLoop): PtNodeGroup { private fun transform(srcUnroll: UnrollLoop): PtNodeGroup {
val result = PtNodeGroup() val result = PtNodeGroup()
repeat(srcUnroll.iterations) { repeat(srcUnroll.iterations.constValue(program)!!.number.toInt()) {
srcUnroll.body.statements.forEach { srcUnroll.body.statements.forEach {
result.add(transformStatement(it)) result.add(transformStatement(it))
} }

View File

@ -583,7 +583,7 @@ private fun Prog8ANTLRParser.RepeatloopContext.toAst(): RepeatLoop {
} }
private fun Prog8ANTLRParser.UnrollloopContext.toAst(): UnrollLoop { 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 statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())
val scope = AnonymousScope(statements, statement_block()?.toPosition() val scope = AnonymousScope(statements, statement_block()?.toPosition()
?: statement().toPosition()) ?: statement().toPosition())

View File

@ -931,11 +931,13 @@ class RepeatLoop(var iterations: Expression?, var body: AnonymousScope, override
iterations?.referencesIdentifier(nameInSource)==true || body.referencesIdentifier(nameInSource) 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 lateinit var parent: Node
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent = parent this.parent = parent
iterations.linkParents(this)
body.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) { override fun replaceChildNode(node: Node, replacement: Node) {
if (node===body) body = replacement as AnonymousScope if (node===body) body = replacement as AnonymousScope
else if (node===iterations) iterations = replacement as Expression
else throw FatalAstException("invalid replace") else throw FatalAstException("invalid replace")
replacement.parent = this replacement.parent = this
} }
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun referencesIdentifier(nameInSource: List<String>): Boolean = body.referencesIdentifier(nameInSource) override fun referencesIdentifier(nameInSource: List<String>): Boolean = iterations.referencesIdentifier(nameInSource) || body.referencesIdentifier(nameInSource)
} }
class UntilLoop(var body: AnonymousScope, class UntilLoop(var body: AnonymousScope,

View File

@ -398,6 +398,7 @@ abstract class AstWalker {
fun visit(unrollLoop: UnrollLoop, parent: Node) { fun visit(unrollLoop: UnrollLoop, parent: Node) {
track(before(unrollLoop, parent), unrollLoop, parent) track(before(unrollLoop, parent), unrollLoop, parent)
unrollLoop.iterations.accept(this, unrollLoop)
unrollLoop.body.accept(this, unrollLoop) unrollLoop.body.accept(this, unrollLoop)
track(after(unrollLoop, parent), unrollLoop, parent) track(after(unrollLoop, parent), unrollLoop, parent)
} }

View File

@ -1,9 +1,6 @@
TODO 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?? - 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 .... - [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 - IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction

View File

@ -1,22 +1,15 @@
%import textio %import textio
%zeropage basicsafe %zeropage dontuse
main { main {
sub start() { 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 index = 100
; ubyte[] t_index = [1,2,3,4,5] ; ubyte[] t_index = [1,2,3,4,5]

View File

@ -299,7 +299,7 @@ untilloop: 'do' (statement | statement_block) EOL? 'until' expression ;
repeatloop: 'repeat' expression? EOL? (statement | statement_block) ; 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? ; whenstmt: 'when' expression EOL? '{' EOL? (when_choice | EOL) * '}' EOL? ;