fix invalid asm label sometimes generated for multiple loops in same subroutine

This commit is contained in:
Irmen de Jong 2022-06-24 02:26:45 +02:00
parent 5656ec11d3
commit eea09f4de5
7 changed files with 80 additions and 56 deletions

View File

@ -18,7 +18,6 @@ import kotlin.io.path.Path
import kotlin.io.path.writeLines
internal const val generatedLabelPrefix = "prog8_label_"
internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
@ -73,13 +72,6 @@ class AsmGen(internal val program: Program,
internal fun isTargetCpu(cpu: CpuType) = options.compTarget.machine.cpu == cpu
private var generatedLabelSequenceNumber: Int = 0
internal fun makeLabel(postfix: String): String {
generatedLabelSequenceNumber++
return "${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix"
}
internal fun outputSourceLine(node: Node) {
out(" ;\tsrc line: ${node.position.file}:${node.position.line}")
}
@ -543,7 +535,7 @@ class AsmGen(internal val program: Program,
if(jump is Jump) {
translateCompareAndJumpIfTrue(booleanCondition, jump)
} else {
val endLabel = makeLabel("if_end")
val endLabel = program.makeLabel("if_end")
translateCompareAndJumpIfFalse(booleanCondition, endLabel)
translate(stmt.truepart)
out(endLabel)
@ -551,8 +543,8 @@ class AsmGen(internal val program: Program,
}
else {
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end")
val elseLabel = program.makeLabel("if_else")
val endLabel = program.makeLabel("if_end")
translateCompareAndJumpIfFalse(booleanCondition, elseLabel)
translate(stmt.truepart)
jmp(endLabel)
@ -568,7 +560,7 @@ class AsmGen(internal val program: Program,
}
private fun translate(stmt: RepeatLoop) {
val endLabel = makeLabel("repeatend")
val endLabel = program.makeLabel("repeatend")
loopEndLabels.push(endLabel)
when (stmt.iterations) {
@ -621,7 +613,7 @@ class AsmGen(internal val program: Program,
private fun repeatWordCount(count: Int, stmt: RepeatLoop) {
require(count in 257..65535)
val repeatLabel = makeLabel("repeat")
val repeatLabel = program.makeLabel("repeat")
if(isTargetCpu(CpuType.CPU65c02)) {
val counterVar = createRepeatCounterVar(DataType.UWORD, true, stmt)
out("""
@ -662,7 +654,7 @@ $repeatLabel""")
private fun repeatWordCountInAY(endLabel: String, stmt: RepeatLoop) {
// note: A/Y must have been loaded with the number of iterations!
// no need to explicitly test for 0 iterations as this is done in the countdown logic below
val repeatLabel = makeLabel("repeat")
val repeatLabel = program.makeLabel("repeat")
val counterVar = createRepeatCounterVar(DataType.UWORD, false, stmt)
out("""
sta $counterVar
@ -683,7 +675,7 @@ $repeatLabel lda $counterVar
private fun repeatByteCount(count: Int, stmt: RepeatLoop) {
require(count in 2..256)
val repeatLabel = makeLabel("repeat")
val repeatLabel = program.makeLabel("repeat")
if(isTargetCpu(CpuType.CPU65c02)) {
val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt)
out(" lda #${count and 255} | sta $counterVar")
@ -701,7 +693,7 @@ $repeatLabel lda $counterVar
private fun repeatCountInY(stmt: RepeatLoop, endLabel: String) {
// note: Y must just have been loaded with the (variable) number of loops to be performed!
val repeatLabel = makeLabel("repeat")
val repeatLabel = program.makeLabel("repeat")
if(isTargetCpu(CpuType.CPU65c02)) {
val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt)
out(" beq $endLabel | sty $counterVar")
@ -738,7 +730,7 @@ $repeatLabel lda $counterVar
}
}
val counterVar = makeLabel("counter")
val counterVar = program.makeLabel("counter")
when(dt) {
DataType.UBYTE, DataType.UWORD -> {
val result = zeropage.allocate(listOf(counterVar), dt, null, stmt.position, errors)
@ -753,7 +745,7 @@ $repeatLabel lda $counterVar
}
private fun translate(stmt: When) {
val endLabel = makeLabel("choice_end")
val endLabel = program.makeLabel("choice_end")
val choiceBlocks = mutableListOf<Pair<String, AnonymousScope>>()
val conditionDt = stmt.condition.inferType(program)
if(!conditionDt.isKnown)
@ -764,7 +756,7 @@ $repeatLabel lda $counterVar
assignExpressionToRegister(stmt.condition, RegisterOrPair.AY)
for(choice in stmt.choices) {
val choiceLabel = makeLabel("choice")
val choiceLabel = program.makeLabel("choice")
if(choice.values==null) {
// the else choice
translate(choice.statements)
@ -828,14 +820,14 @@ $repeatLabel lda $counterVar
} else {
if(stmt.elsepart.isEmpty()) {
val instruction = branchInstruction(stmt.condition, true)
val elseLabel = makeLabel("branch_else")
val elseLabel = program.makeLabel("branch_else")
out(" $instruction $elseLabel")
translate(stmt.truepart)
out(elseLabel)
} else {
val instruction = branchInstruction(stmt.condition, true)
val elseLabel = makeLabel("branch_else")
val endLabel = makeLabel("branch_end")
val elseLabel = program.makeLabel("branch_else")
val endLabel = program.makeLabel("branch_end")
out(" $instruction $elseLabel")
translate(stmt.truepart)
jmp(endLabel)

View File

@ -3,6 +3,7 @@ package prog8.codegen.cpu6502
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.mapError
import prog8.ast.generatedLabelPrefix
import prog8.code.core.*
import java.io.File
import java.nio.file.Path

View File

@ -31,10 +31,10 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
}
private fun translateForOverNonconstRange(stmt: ForLoop, iterableDt: DataType, range: RangeExpression) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
val modifiedLabel = asmgen.makeLabel("for_modified")
val modifiedLabel2 = asmgen.makeLabel("for_modifiedb")
val loopLabel = program.makeLabel("for_loop")
val endLabel = program.makeLabel("for_end")
val modifiedLabel = program.makeLabel("for_modified")
val modifiedLabel2 = program.makeLabel("for_modifiedb")
asmgen.loopEndLabels.push(endLabel)
val stepsize=range.step.constValue(program)!!.number.toInt()
@ -238,8 +238,8 @@ $endLabel""")
}
private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
val loopLabel = program.makeLabel("for_loop")
val endLabel = program.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val iterableName = asmgen.asmVariableName(ident)
val decl = ident.targetVarDecl(program)!!
@ -263,7 +263,7 @@ $endLabel""")
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {
val length = decl.arraysize!!.constIndex()!!
val indexVar = asmgen.makeLabel("for_index")
val indexVar = program.makeLabel("for_index")
asmgen.out("""
ldy #0
$loopLabel sty $indexVar
@ -299,7 +299,7 @@ $loopLabel sty $indexVar
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
val length = decl.arraysize!!.constIndex()!! * 2
val indexVar = asmgen.makeLabel("for_index")
val indexVar = program.makeLabel("for_index")
val loopvarName = asmgen.asmVariableName(stmt.loopVar)
asmgen.out("""
ldy #0
@ -359,8 +359,8 @@ $loopLabel sty $indexVar
}
// not one of the easy cases, generate more complex code...
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
val loopLabel = program.makeLabel("for_loop")
val endLabel = program.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
when(iterableDt) {
DataType.ARRAY_B, DataType.ARRAY_UB -> {
@ -471,8 +471,8 @@ $loopLabel""")
}
private fun translateForSimpleByteRangeAsc(stmt: ForLoop, range: IntProgression) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
val loopLabel = program.makeLabel("for_loop")
val endLabel = program.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.out("""
@ -497,8 +497,8 @@ $endLabel""")
}
private fun translateForSimpleByteRangeDesc(stmt: ForLoop, range: IntProgression) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
val loopLabel = program.makeLabel("for_loop")
val endLabel = program.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.out("""
@ -534,8 +534,8 @@ $endLabel""")
}
private fun translateForSimpleWordRangeAsc(stmt: ForLoop, range: IntProgression) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
val loopLabel = program.makeLabel("for_loop")
val endLabel = program.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.out("""
@ -561,8 +561,8 @@ $loopLabel""")
}
private fun translateForSimpleWordRangeDesc(stmt: ForLoop, range: IntProgression) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
val loopLabel = program.makeLabel("for_loop")
val endLabel = program.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.out("""

View File

@ -12,9 +12,8 @@ import prog8.code.core.IErrorReporter
import prog8.code.core.Position
private var generatedLabelSequenceNumber: Int = 0
internal class CodeDesugarer(val program: Program, private val errors: IErrorReporter) : AstWalker() {
internal class CodeDesugarer(val program: Program,
private val errors: IErrorReporter) : AstWalker() {
// Some more code shuffling to simplify the Ast that the codegenerator has to process.
// Several changes have already been done by the StatementReorderer !
@ -28,13 +27,6 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep
// - repeat-forever loops replaced by label+jump.
private val generatedLabelPrefix = "prog8_label_"
private fun makeLabel(postfix: String, position: Position): Label {
generatedLabelSequenceNumber++
return Label("${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix", position)
}
private fun jumpLabel(label: Label): Jump {
val ident = IdentifierReference(listOf(label.name), label.position)
return Jump(null, ident, null, label.position)
@ -42,7 +34,7 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
fun jumpAfter(stmt: Statement): Iterable<IAstModification> {
val label = makeLabel("after", breakStmt.position)
val label = program.makeLabel("after", breakStmt.position)
return listOf(
IAstModification.ReplaceNode(breakStmt, jumpLabel(label), parent),
IAstModification.InsertAfter(stmt, label, stmt.parent as IStatementContainer)
@ -75,7 +67,7 @@ if not CONDITION
goto _loop
*/
val pos = untilLoop.position
val loopLabel = makeLabel("untilloop", pos)
val loopLabel = program.makeLabel("untilloop", pos)
val notCondition = PrefixExpression("not", untilLoop.condition, pos)
val replacement = AnonymousScope(mutableListOf(
loopLabel,
@ -99,8 +91,8 @@ _whileloop:
_after:
*/
val pos = whileLoop.position
val loopLabel = makeLabel("whileloop", pos)
val afterLabel = makeLabel("afterwhile", pos)
val loopLabel = program.makeLabel("whileloop", pos)
val afterLabel = program.makeLabel("afterwhile", pos)
val notCondition = PrefixExpression("not", whileLoop.condition, pos)
val replacement = AnonymousScope(mutableListOf(
loopLabel,
@ -138,7 +130,7 @@ _after:
override fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> {
if(repeatLoop.iterations==null) {
val label = makeLabel("repeat", repeatLoop.position)
val label = program.makeLabel("repeat", repeatLoop.position)
val jump = jumpLabel(label)
return listOf(
IAstModification.InsertFirst(label, repeatLoop.body),

View File

@ -2,6 +2,7 @@ package prog8tests.codegeneration
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.expressions.AddressOf
@ -13,10 +14,12 @@ import prog8.code.target.C64Target
import prog8.code.target.c64.C64Zeropage
import prog8.codegen.cpu6502.AsmGen
import prog8.compiler.astprocessing.SymbolTableMaker
import prog8tests.helpers.*
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
class TestAsmGenSymbols: StringSpec({
fun createTestProgram(): Program {
@ -153,4 +156,26 @@ main {
asmgen.asmSymbolName(id1) shouldBe "P8ZP_SCRATCH_REG"
asmgen.asmSymbolName(id2) shouldBe "P8ZP_SCRATCH_W2"
}
"no double labels with various loops" {
val text="""
main {
sub start() {
if true {
}
repeat 4 {
}
while true {
}
repeat {
}
}
}
"""
val result = compileText(C64Target(), false, text, writeAssembly = true)
result shouldNotBe null
}
})

View File

@ -143,4 +143,19 @@ class Program(val name: String,
}
}
private var generatedLabelSequenceNumber: Int = 0
fun makeLabel(postfix: String): String {
generatedLabelSequenceNumber++
return "${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix"
}
fun makeLabel(postfix: String, position: Position): Label {
val strLabel = makeLabel(postfix)
return Label(strLabel, position)
}
}
const val generatedLabelPrefix = "prog8_label_"

View File

@ -3,7 +3,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- bug: 2 repeats in same subroutine -> duplicate label error? see repeat_bug.p8
- bug: f_read() can't deal with running out of banked ram? maybe only cx16diskio.f_read()?
- add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments!
- add some more optimizations in vmPeepholeOptimizer