mirror of
https://github.com/irmen/prog8.git
synced 2025-02-27 03:29:22 +00:00
rename
This commit is contained in:
parent
39d6d2857e
commit
2340760f53
@ -63,9 +63,9 @@ class IRCodeGen(
|
||||
// for instance when a piece of inlined assembly references them.
|
||||
val replacements = mutableListOf<Triple<IRCodeChunkBase, Int, UInt>>()
|
||||
irProg.blocks.asSequence().flatMap { it.subroutines }.flatMap { it.chunks }.forEach { chunk ->
|
||||
chunk.lines.withIndex().forEach {
|
||||
(lineIndex, line) -> if(line is IRInstruction) {
|
||||
val symbolExpr = line.labelSymbol
|
||||
chunk.instructions.withIndex().forEach {
|
||||
(idx, instr) -> if(instr is IRInstruction) {
|
||||
val symbolExpr = instr.labelSymbol
|
||||
if(symbolExpr!=null) {
|
||||
val symbol: String
|
||||
val index: UInt
|
||||
@ -79,7 +79,7 @@ class IRCodeGen(
|
||||
}
|
||||
val target = symbolTable.flat[symbol.split('.')]
|
||||
if (target is StMemVar) {
|
||||
replacements.add(Triple(chunk, lineIndex, target.address+index))
|
||||
replacements.add(Triple(chunk, idx, target.address+index))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,8 +87,8 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
replacements.forEach {
|
||||
val old = it.first.lines[it.second] as IRInstruction
|
||||
it.first.lines[it.second] = IRInstruction(
|
||||
val old = it.first.instructions[it.second] as IRInstruction
|
||||
it.first.instructions[it.second] = IRInstruction(
|
||||
old.opcode,
|
||||
old.type,
|
||||
old.reg1,
|
||||
|
@ -10,7 +10,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
// we don't optimize Inline Asm chunks here.
|
||||
if(chunk is IRCodeChunk) {
|
||||
do {
|
||||
val indexedInstructions = chunk.lines.withIndex()
|
||||
val indexedInstructions = chunk.instructions.withIndex()
|
||||
.filter { it.value is IRInstruction }
|
||||
.map { IndexedValue(it.index, it.value as IRInstruction) }
|
||||
val changed = removeNops(chunk, indexedInstructions)
|
||||
@ -51,7 +51,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
chunks += sub.chunks[0]
|
||||
for(ix in 1 until sub.chunks.size) {
|
||||
if(mayJoin(chunks.last(), sub.chunks[ix]))
|
||||
chunks.last().lines += sub.chunks[ix].lines
|
||||
chunks.last().instructions += sub.chunks[ix].instructions
|
||||
else
|
||||
chunks += sub.chunks[ix]
|
||||
}
|
||||
@ -64,15 +64,15 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if(ins.opcode== Opcode.PUSH) {
|
||||
if(idx < chunk.lines.size-1) {
|
||||
val insAfter = chunk.lines[idx+1] as? IRInstruction
|
||||
if(idx < chunk.instructions.size-1) {
|
||||
val insAfter = chunk.instructions[idx+1] as? IRInstruction
|
||||
if(insAfter!=null && insAfter.opcode == Opcode.POP) {
|
||||
if(ins.reg1==insAfter.reg1) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
} else {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOADR, ins.type, reg1=insAfter.reg1, reg2=ins.reg1)
|
||||
chunk.lines.removeAt(idx+1)
|
||||
chunk.instructions[idx] = IRInstruction(Opcode.LOADR, ins.type, reg1=insAfter.reg1, reg2=ins.reg1)
|
||||
chunk.instructions.removeAt(idx+1)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
@ -88,18 +88,18 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if(ins.opcode== Opcode.SEC || ins.opcode== Opcode.CLC) {
|
||||
if(idx < chunk.lines.size-1) {
|
||||
val insAfter = chunk.lines[idx+1] as? IRInstruction
|
||||
if(idx < chunk.instructions.size-1) {
|
||||
val insAfter = chunk.instructions[idx+1] as? IRInstruction
|
||||
if(insAfter?.opcode == ins.opcode) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
else if(ins.opcode== Opcode.SEC && insAfter?.opcode== Opcode.CLC) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
else if(ins.opcode== Opcode.CLC && insAfter?.opcode== Opcode.SEC) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
@ -114,19 +114,19 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
val labelSymbol = ins.labelSymbol
|
||||
if(ins.opcode== Opcode.JUMP && labelSymbol!=null) {
|
||||
// remove jump/branch to label immediately below
|
||||
if(idx < chunk.lines.size-1) {
|
||||
val label = chunk.lines[idx+1] as? IRCodeLabel
|
||||
if(idx < chunk.instructions.size-1) {
|
||||
val label = chunk.instructions[idx+1] as? IRCodeLabel
|
||||
if(label?.name == labelSymbol) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove useless RETURN
|
||||
if(ins.opcode == Opcode.RETURN && idx>0) {
|
||||
val previous = chunk.lines[idx-1] as? IRInstruction
|
||||
val previous = chunk.instructions[idx-1] as? IRInstruction
|
||||
if(previous?.opcode in setOf(Opcode.JUMP, Opcode.JUMPA, Opcode.RETURN)) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
@ -141,47 +141,47 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
when (ins.opcode) {
|
||||
Opcode.DIV, Opcode.DIVS, Opcode.MUL, Opcode.MOD -> {
|
||||
if (ins.value == 1) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.ADD, Opcode.SUB -> {
|
||||
if (ins.value == 1) {
|
||||
chunk.lines[idx] = IRInstruction(
|
||||
chunk.instructions[idx] = IRInstruction(
|
||||
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
|
||||
ins.type,
|
||||
ins.reg1
|
||||
)
|
||||
changed = true
|
||||
} else if (ins.value == 0) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.AND -> {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
|
||||
chunk.instructions[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
|
||||
changed = true
|
||||
} else if (ins.value == 255 && ins.type == IRDataType.BYTE) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
} else if (ins.value == 65535 && ins.type == IRDataType.WORD) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.OR -> {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
} else if ((ins.value == 255 && ins.type == IRDataType.BYTE) || (ins.value == 65535 && ins.type == IRDataType.WORD)) {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
|
||||
chunk.instructions[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.XOR -> {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
@ -196,7 +196,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if (ins.opcode == Opcode.NOP) {
|
||||
changed = true
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.instructions.removeAt(idx)
|
||||
}
|
||||
}
|
||||
return changed
|
||||
|
@ -6,12 +6,12 @@ import prog8.codegen.intermediate.IRPeepholeOptimizer
|
||||
import prog8.intermediate.*
|
||||
|
||||
class TestIRPeepholeOpt: FunSpec({
|
||||
fun makeIRProgram(lines: List<IRCodeLine>): IRProgram {
|
||||
fun makeIRProgram(instructions: List<IRCodeLine>): IRProgram {
|
||||
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||
val sub = IRSubroutine("main.start", emptyList(), null, Position.DUMMY)
|
||||
val chunk = IRCodeChunk(Position.DUMMY)
|
||||
for(line in lines)
|
||||
chunk += line
|
||||
for(instr in instructions)
|
||||
chunk += instr
|
||||
sub += chunk
|
||||
block += sub
|
||||
val target = VMTarget()
|
||||
@ -30,7 +30,7 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
return prog
|
||||
}
|
||||
|
||||
fun IRProgram.lines(): List<IRCodeLine> = this.blocks.flatMap { it.subroutines }.flatMap { it.chunks }.flatMap { it.lines }
|
||||
fun IRProgram.instructions(): List<IRCodeLine> = this.blocks.flatMap { it.subroutines }.flatMap { it.chunks }.flatMap { it.instructions }
|
||||
|
||||
test("remove nops") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
@ -38,10 +38,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.NOP),
|
||||
IRInstruction(Opcode.NOP)
|
||||
))
|
||||
irProg.lines().size shouldBe 3
|
||||
irProg.instructions().size shouldBe 3
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
irProg.lines().size shouldBe 1
|
||||
irProg.instructions().size shouldBe 1
|
||||
}
|
||||
|
||||
test("remove jmp to label below") {
|
||||
@ -55,10 +55,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1),
|
||||
IRCodeLabel("label3")
|
||||
))
|
||||
irProg.lines().size shouldBe 8
|
||||
irProg.instructions().size shouldBe 8
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 5
|
||||
(lines[0] as IRCodeLabel).name shouldBe "label"
|
||||
(lines[1] as IRCodeLabel).name shouldBe "label2"
|
||||
@ -76,10 +76,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.CLC),
|
||||
IRInstruction(Opcode.CLC)
|
||||
))
|
||||
irProg.lines().size shouldBe 6
|
||||
irProg.instructions().size shouldBe 6
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.CLC
|
||||
}
|
||||
@ -91,10 +91,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=99),
|
||||
IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=222)
|
||||
))
|
||||
irProg.lines().size shouldBe 4
|
||||
irProg.instructions().size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOADR
|
||||
(lines[0] as IRInstruction).reg1 shouldBe 222
|
||||
@ -114,10 +114,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 0)
|
||||
))
|
||||
irProg.lines().size shouldBe 10
|
||||
irProg.instructions().size shouldBe 10
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 4
|
||||
}
|
||||
|
||||
@ -126,10 +126,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.lines().size shouldBe 2
|
||||
irProg.instructions().size shouldBe 2
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 2
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.INC
|
||||
(lines[1] as IRInstruction).opcode shouldBe Opcode.DEC
|
||||
@ -146,10 +146,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.XOR, IRDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.lines().size shouldBe 8
|
||||
irProg.instructions().size shouldBe 8
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 4
|
||||
}
|
||||
|
||||
@ -160,10 +160,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, value = 65535)
|
||||
))
|
||||
irProg.lines().size shouldBe 4
|
||||
irProg.instructions().size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 4
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[1] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
|
@ -3,6 +3,9 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- ir: get rid of IRCodeLabel, make every label start a new code chunk, give those a 'label' property.
|
||||
- ir: fix joinChunks() in the IR optimizer ?
|
||||
|
||||
...
|
||||
|
||||
|
||||
@ -19,8 +22,6 @@ Compiler:
|
||||
|
||||
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
|
||||
- ir: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
|
||||
- ir: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether during execution/translation.
|
||||
- ir: joinChunks() in the IR optimizer should be changed accordingly
|
||||
- ir: add more optimizations in IRPeepholeOptimizer
|
||||
- ir: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
|
||||
- see if we can let for loops skip the loop if end<start, like other programming languages. Without adding a lot of code size/duplicating the loop condition.
|
||||
|
@ -11,7 +11,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
|
||||
private val out = outfile.bufferedWriter()
|
||||
private var numChunks = 0
|
||||
private var numLines = 0
|
||||
private var numInstr = 0
|
||||
|
||||
|
||||
fun write(): Path {
|
||||
@ -35,7 +35,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
|
||||
val used = irProgram.registersUsed()
|
||||
val numberUsed = (used.inputRegs.keys + used.outputRegs.keys).size + (used.inputFpRegs.keys + used.outputFpRegs.keys).size
|
||||
println("($numLines lines in $numChunks code chunks, $numberUsed registers)")
|
||||
println("($numInstr instructions in $numChunks chunks, $numberUsed registers)")
|
||||
return outfile
|
||||
}
|
||||
|
||||
@ -63,11 +63,11 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
is IRInlineBinaryChunk -> writeInlineBytes(chunk)
|
||||
else -> {
|
||||
out.write("<C>\n")
|
||||
if (chunk.lines.isEmpty())
|
||||
if (chunk.instructions.isEmpty())
|
||||
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
|
||||
chunk.lines.forEach { line ->
|
||||
numLines++
|
||||
out.writeLine(line)
|
||||
chunk.instructions.forEach { instr ->
|
||||
numInstr++
|
||||
out.writeLine(instr)
|
||||
}
|
||||
out.write("</C>\n")
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class IRProgram(val name: String,
|
||||
val globalInits = mutableListOf<IRCodeLine>()
|
||||
val blocks = mutableListOf<IRBlock>()
|
||||
|
||||
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.lines)
|
||||
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.instructions)
|
||||
fun addBlock(block: IRBlock) {
|
||||
require(blocks.all { it.name != block.name}) { "duplicate block ${block.name} ${block.position}" }
|
||||
blocks.add(block)
|
||||
@ -68,11 +68,11 @@ class IRProgram(val name: String,
|
||||
fun validate() {
|
||||
blocks.forEach {
|
||||
it.inlineAssembly.forEach { chunk ->
|
||||
require(chunk.lines.isEmpty())
|
||||
require(chunk.instructions.isEmpty())
|
||||
}
|
||||
it.subroutines.forEach { sub ->
|
||||
sub.chunks.forEach { chunk ->
|
||||
if (chunk is IRInlineAsmChunk) { require(chunk.lines.isEmpty()) }
|
||||
if (chunk is IRInlineAsmChunk) { require(chunk.instructions.isEmpty()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,7 +176,7 @@ sealed class IRCodeLine
|
||||
class IRCodeLabel(val name: String): IRCodeLine()
|
||||
|
||||
abstract class IRCodeChunkBase(val position: Position) {
|
||||
val lines = mutableListOf<IRCodeLine>()
|
||||
val instructions = mutableListOf<IRCodeLine>()
|
||||
|
||||
abstract fun isEmpty(): Boolean
|
||||
abstract fun isNotEmpty(): Boolean
|
||||
@ -185,14 +185,14 @@ abstract class IRCodeChunkBase(val position: Position) {
|
||||
|
||||
class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
|
||||
|
||||
override fun isEmpty() = lines.isEmpty()
|
||||
override fun isNotEmpty() = lines.isNotEmpty()
|
||||
override fun isEmpty() = instructions.isEmpty()
|
||||
override fun isNotEmpty() = instructions.isNotEmpty()
|
||||
override fun usedRegisters(): RegistersUsed {
|
||||
val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
lines.forEach {
|
||||
instructions.forEach {
|
||||
if(it is IRInstruction)
|
||||
it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
|
||||
}
|
||||
@ -200,11 +200,11 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
|
||||
}
|
||||
|
||||
operator fun plusAssign(line: IRCodeLine) {
|
||||
lines.add(line)
|
||||
instructions.add(line)
|
||||
}
|
||||
|
||||
operator fun plusAssign(chunk: IRCodeChunkBase) {
|
||||
lines.addAll(chunk.lines)
|
||||
instructions.addAll(chunk.instructions)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ class VmProgramLoader {
|
||||
when (chunk) {
|
||||
is IRInlineAsmChunk -> addAssemblyToProgram(chunk, program, symbolAddresses)
|
||||
is IRInlineBinaryChunk -> program += IRInstruction(Opcode.BINARYDATA, binaryData = chunk.data)
|
||||
else -> addToProgram(chunk.lines, program, symbolAddresses)
|
||||
else -> addToProgram(chunk.instructions, program, symbolAddresses)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,11 +187,11 @@ class VmProgramLoader {
|
||||
}
|
||||
|
||||
private fun addToProgram(
|
||||
lines: Iterable<IRCodeLine>,
|
||||
instructions: Iterable<IRCodeLine>,
|
||||
program: MutableList<IRInstruction>,
|
||||
symbolAddresses: MutableMap<String, Int>
|
||||
) {
|
||||
lines.map {
|
||||
instructions.map {
|
||||
when(it) {
|
||||
is IRInstruction -> {
|
||||
it.labelSymbol?.let { symbol -> placeholders[program.size]=symbol }
|
||||
|
@ -61,8 +61,8 @@ class TestVm: FunSpec( {
|
||||
vm.memory.getUW(1000) shouldBe 12345u
|
||||
vm.callStack.shouldBeEmpty()
|
||||
vm.valueStack.shouldBeEmpty()
|
||||
vm.pc shouldBe code.lines.size-1
|
||||
vm.stepCount shouldBe code.lines.size
|
||||
vm.pc shouldBe code.instructions.size-1
|
||||
vm.stepCount shouldBe code.instructions.size
|
||||
}
|
||||
|
||||
test("vm asmsub not supported") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user