Files
prog8/codeGenNew6502/test/TestLoopCodegen.kt
T
2026-09-11 20:20:40 +02:00

75 lines
3.0 KiB
Kotlin

package prog8tests.codegen.new6502
import io.kotest.core.spec.style.FunSpec
import io.kotest.engine.spec.tempdir
import io.kotest.matchers.shouldBe
import prog8.code.core.CompilationOptions
import prog8.code.core.OutputType
import prog8.code.core.Position
import prog8.code.core.ZeropageType
import prog8.code.target.Cx16Target
import prog8.codegen.new6502.AsmGen
import prog8.intermediate.*
import prog8tests.helpers.ErrorReporterForTests
import kotlin.io.path.exists
import kotlin.io.path.readText
/**
* Regression tests for counted-loop code generation in the new 6502 backend.
*/
class TestLoopCodegen : FunSpec({
val tempRoot = tempdir().toPath()
fun generateAsmForLoop(loop: IRLoopChunk): List<String> {
val target = Cx16Target()
val options = CompilationOptions.builder(target)
.output(OutputType.RAW)
.zeropage(ZeropageType.FLOATSAFE)
.floats(false)
.compilerVersion("test")
.memtopAddress(0xffffu)
.optimize(true)
.build()
val program = IRProgram("test", IRSymbolTable(), options, DummyStringEncoder)
val outputDir = tempRoot.resolve("test-new6502-loop-${System.nanoTime()}")
program.options.outputDir = outputDir
val sub = IRSubroutine("test.start", emptyList(), emptyList(), Position.DUMMY)
sub.chunks.add(loop)
val block = IRBlock("test", false, IRBlock.Options(), Position.DUMMY)
block.children.add(sub)
program.blocks.add(block)
outputDir.toFile().deleteRecursively()
outputDir.toFile().mkdirs()
AsmGen(program, target, ErrorReporterForTests()).generate()
val asmFile = outputDir.resolve("test.asm")
check(asmFile.exists()) { "Assembly file not written: $asmFile" }
return asmFile.readText().lines().map { it.trimStart() }
}
test("IRLoopChunk uses Y as counter") {
val body = IRCodeChunk(null, null).also {
it += IRInstructions.memoryOp(Opcode.INCM, IRDataType.BYTE, IRMemory.direct("p8b_main.p8v_sum"))
}
val loop = IRLoopChunk("p8_label_gen_1", 5, mutableListOf(body))
val lines = generateAsmForLoop(loop)
lines.any { it.startsWith("ldy #5") } shouldBe true
lines.any { it.startsWith("dey") } shouldBe true
lines.any { it.startsWith("bne p8_label_gen_1") } shouldBe true
}
test("IRLoopChunk preserves Y around body chunk that uses Y") {
val body = IRCodeChunk(null, null).also {
it += IRInstructions.storeMemory(Opcode.STOREI, IRDataType.BYTE, 2, IRMemory.indirect(3))
}
val loop = IRLoopChunk("p8_label_gen_1", 5, mutableListOf(body))
val lines = generateAsmForLoop(loop)
lines.any { it.startsWith("ldy #5") } shouldBe true
lines.any { it.startsWith("tya") } shouldBe true
lines.any { it.startsWith("pha") } shouldBe true
lines.any { it.startsWith("pla") } shouldBe true
lines.any { it.startsWith("tay") } shouldBe true
}
})