From 29dd7583022a6d2dc5b0fe2dc186e74b6a59bdfa Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 5 Sep 2024 21:23:17 +0200 Subject: [PATCH] Fix compiler crash in for loops with just 1 iteration --- codeCore/src/prog8/code/ast/AstExpressions.kt | 1 + .../prog8/codegen/cpu6502/ForLoopsAsmGen.kt | 4 +- compiler/res/prog8lib/cx16/graphics.p8 | 8 ++ .../test/codegeneration/TestVariousCodeGen.kt | 37 +++++++++ .../prog8/ast/expressions/AstExpressions.kt | 1 + docs/source/todo.rst | 3 - examples/test.p8 | 76 +++++++++++-------- 7 files changed, 95 insertions(+), 35 deletions(-) diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index c4e470154..e6f29df2f 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -296,6 +296,7 @@ class PtRange(type: DataType, position: Position) : PtExpression(type, position) fun toConstantIntegerRange(): IntProgression? { fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression { return when { + fromVal == toVal -> fromVal .. toVal fromVal <= toVal -> when { stepVal <= 0 -> IntRange.EMPTY stepVal == 1 -> fromVal..toVal diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index d358d0031..a1b566a6f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -484,10 +484,12 @@ $loopLabel sty $indexVar if (range.isEmpty() || range.step==0) throw AssemblyError("empty range or step 0") if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) { + if(range.last==range.first) return translateForSimpleByteRangeAsc(stmt, range) if(range.step==1 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range) if(range.step==-1 && range.lastrange.first) return translateForSimpleWordRangeAsc(stmt, range) if(range.step==-1 && range.last { - throw AssemblyError("step 0, 1 and -1 should have been handled specifically $stmt") + throw AssemblyError("step 0, 1 and -1 should have been handled specifically $range ${stmt.position}") } 2 -> { if(range.last==255 || range.last==254) { diff --git a/compiler/res/prog8lib/cx16/graphics.p8 b/compiler/res/prog8lib/cx16/graphics.p8 index b234949ee..a0c4fd395 100644 --- a/compiler/res/prog8lib/cx16/graphics.p8 +++ b/compiler/res/prog8lib/cx16/graphics.p8 @@ -101,4 +101,12 @@ graphics { return cx16.GRAPH_draw_oval(xcenter - h_radius, ycenter - v_radius, h_radius*2, v_radius*2, true) } + + inline asmsub plot(uword plotx @R0, uword ploty @R1) clobbers(A, X, Y) { + %asm {{ + jsr cx16.FB_cursor_position + lda p8b_graphics.p8v_stroke_color + jsr cx16.FB_set_pixel + }} + } } diff --git a/compiler/test/codegeneration/TestVariousCodeGen.kt b/compiler/test/codegeneration/TestVariousCodeGen.kt index 627ca1d9e..2fffdacc6 100644 --- a/compiler/test/codegeneration/TestVariousCodeGen.kt +++ b/compiler/test/codegeneration/TestVariousCodeGen.kt @@ -383,4 +383,41 @@ main { compileText(AtariTarget(), false, text, writeAssembly = true) shouldNotBe null compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null } + + test("for loops with just 1 iteration") { + val src=""" +main { + sub start() { + for cx16.r0L in 100 downto 100 { + cx16.r1++ + } + for cx16.r0L in 100 to 100 { + cx16.r1++ + } + for cx16.r0 in 2222 downto 2222 { + cx16.r1++ + } + for cx16.r0 in 2222 to 2222 { + cx16.r1++ + } + + for cx16.r0L in 100 downto 100 step -5 { + cx16.r1++ + } + for cx16.r0L in 100 to 100 step 5 { + cx16.r1++ + } + for cx16.r0 in 2222 downto 2222 step -5 { + cx16.r1++ + } + for cx16.r0 in 2222 to 2222 step 5 { + cx16.r1++ + } + } +}""" + compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null + compileText(VMTarget(), false, src, writeAssembly = true) shouldNotBe null + compileText(Cx16Target(), true, src, writeAssembly = true) shouldNotBe null + compileText(Cx16Target(), false, src, writeAssembly = true) shouldNotBe null + } }) \ No newline at end of file diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index a5cdc6428..abdd2edeb 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -1006,6 +1006,7 @@ class RangeExpression(var from: Expression, fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression { return when { + fromVal == toVal -> fromVal .. toVal fromVal <= toVal -> when { stepVal <= 0 -> IntRange.EMPTY stepVal == 1 -> fromVal..toVal diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 8a23c4c87..6970397ea 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,9 +1,6 @@ TODO ==== -Fix compiler crash for: for radius in 100 downto 100 step -10 - - Improve register load order in subroutine call args assignments: in certain situations, the "wrong" order of evaluation of function call arguments is done which results in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!) diff --git a/examples/test.p8 b/examples/test.p8 index 121cfee84..cea274579 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,39 +1,53 @@ -%import gfx2 %import textio -%import math -%option no_sysinit %zeropage basicsafe - main { - sub start() { - gfx2.screen_mode(2) - demofill() - } - - sub demofill() { - gfx2.circle(160, 120, 110, 1) - gfx2.rect(180, 5, 25, 190, 2) - gfx2.line(100, 150, 240, 10, 2) - gfx2.rect(150, 130, 10, 100, 3) - - sys.wait(30) - - cbm.SETTIM(0,0,0) - gfx2.fill(100,100,3) - gfx2.fill(100,100,2) - gfx2.fill(100,100,0) - uword duration = cbm.RDTIM16() - sys.wait(30) - - gfx2.screen_mode(0) - txt.nl() - txt.print_uw(duration) - txt.print(" jiffies\n") - - ; hires 4c before optimizations: ~345 jiffies - + for cx16.r0L in 5 to 5 { + txt.print("derp0.") + txt.print_ub(cx16.r0L) + txt.nl() + } + for cx16.r0L in 100 downto 100 { + txt.print("derp1.") + txt.print_ub(cx16.r0L) + txt.nl() + } + for cx16.r0L in 100 to 100 { + txt.print("derp2.") + txt.print_ub(cx16.r0L) + txt.nl() + } + for cx16.r0 in 2222 downto 2222 { + txt.print("derp3.") + txt.print_uw(cx16.r0) + txt.nl() + } + for cx16.r0 in 2222 to 2222 { + txt.print("derp4.") + txt.print_uw(cx16.r0) + txt.nl() + } + for cx16.r0L in 100 downto 100 step -5 { + txt.print("derp5.") + txt.print_ub(cx16.r0L) + txt.nl() + } + for cx16.r0L in 100 to 100 step 5 { + txt.print("derp6.") + txt.print_ub(cx16.r0L) + txt.nl() + } + for cx16.r0 in 2222 downto 2222 step -5 { + txt.print("derp7.") + txt.print_uw(cx16.r0) + txt.nl() + } + for cx16.r0 in 2222 to 2222 step 5 { + txt.print("derp8.") + txt.print_uw(cx16.r0) + txt.nl() + } } }