This commit is contained in:
Irmen de Jong 2022-10-04 22:54:14 +02:00
parent 39d6d2857e
commit 2340760f53
8 changed files with 77 additions and 76 deletions

View File

@ -63,9 +63,9 @@ class IRCodeGen(
// for instance when a piece of inlined assembly references them. // for instance when a piece of inlined assembly references them.
val replacements = mutableListOf<Triple<IRCodeChunkBase, Int, UInt>>() val replacements = mutableListOf<Triple<IRCodeChunkBase, Int, UInt>>()
irProg.blocks.asSequence().flatMap { it.subroutines }.flatMap { it.chunks }.forEach { chunk -> irProg.blocks.asSequence().flatMap { it.subroutines }.flatMap { it.chunks }.forEach { chunk ->
chunk.lines.withIndex().forEach { chunk.instructions.withIndex().forEach {
(lineIndex, line) -> if(line is IRInstruction) { (idx, instr) -> if(instr is IRInstruction) {
val symbolExpr = line.labelSymbol val symbolExpr = instr.labelSymbol
if(symbolExpr!=null) { if(symbolExpr!=null) {
val symbol: String val symbol: String
val index: UInt val index: UInt
@ -79,7 +79,7 @@ class IRCodeGen(
} }
val target = symbolTable.flat[symbol.split('.')] val target = symbolTable.flat[symbol.split('.')]
if (target is StMemVar) { 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 { replacements.forEach {
val old = it.first.lines[it.second] as IRInstruction val old = it.first.instructions[it.second] as IRInstruction
it.first.lines[it.second] = IRInstruction( it.first.instructions[it.second] = IRInstruction(
old.opcode, old.opcode,
old.type, old.type,
old.reg1, old.reg1,

View File

@ -10,7 +10,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
// we don't optimize Inline Asm chunks here. // we don't optimize Inline Asm chunks here.
if(chunk is IRCodeChunk) { if(chunk is IRCodeChunk) {
do { do {
val indexedInstructions = chunk.lines.withIndex() val indexedInstructions = chunk.instructions.withIndex()
.filter { it.value is IRInstruction } .filter { it.value is IRInstruction }
.map { IndexedValue(it.index, it.value as IRInstruction) } .map { IndexedValue(it.index, it.value as IRInstruction) }
val changed = removeNops(chunk, indexedInstructions) val changed = removeNops(chunk, indexedInstructions)
@ -51,7 +51,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
chunks += sub.chunks[0] chunks += sub.chunks[0]
for(ix in 1 until sub.chunks.size) { for(ix in 1 until sub.chunks.size) {
if(mayJoin(chunks.last(), sub.chunks[ix])) if(mayJoin(chunks.last(), sub.chunks[ix]))
chunks.last().lines += sub.chunks[ix].lines chunks.last().instructions += sub.chunks[ix].instructions
else else
chunks += sub.chunks[ix] chunks += sub.chunks[ix]
} }
@ -64,15 +64,15 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
var changed = false var changed = false
indexedInstructions.reversed().forEach { (idx, ins) -> indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode== Opcode.PUSH) { if(ins.opcode== Opcode.PUSH) {
if(idx < chunk.lines.size-1) { if(idx < chunk.instructions.size-1) {
val insAfter = chunk.lines[idx+1] as? IRInstruction val insAfter = chunk.instructions[idx+1] as? IRInstruction
if(insAfter!=null && insAfter.opcode == Opcode.POP) { if(insAfter!=null && insAfter.opcode == Opcode.POP) {
if(ins.reg1==insAfter.reg1) { if(ins.reg1==insAfter.reg1) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
} else { } else {
chunk.lines[idx] = IRInstruction(Opcode.LOADR, ins.type, reg1=insAfter.reg1, reg2=ins.reg1) chunk.instructions[idx] = IRInstruction(Opcode.LOADR, ins.type, reg1=insAfter.reg1, reg2=ins.reg1)
chunk.lines.removeAt(idx+1) chunk.instructions.removeAt(idx+1)
} }
changed = true changed = true
} }
@ -88,18 +88,18 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
var changed = false var changed = false
indexedInstructions.reversed().forEach { (idx, ins) -> indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode== Opcode.SEC || ins.opcode== Opcode.CLC) { if(ins.opcode== Opcode.SEC || ins.opcode== Opcode.CLC) {
if(idx < chunk.lines.size-1) { if(idx < chunk.instructions.size-1) {
val insAfter = chunk.lines[idx+1] as? IRInstruction val insAfter = chunk.instructions[idx+1] as? IRInstruction
if(insAfter?.opcode == ins.opcode) { if(insAfter?.opcode == ins.opcode) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
else if(ins.opcode== Opcode.SEC && insAfter?.opcode== Opcode.CLC) { else if(ins.opcode== Opcode.SEC && insAfter?.opcode== Opcode.CLC) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
else if(ins.opcode== Opcode.CLC && insAfter?.opcode== Opcode.SEC) { else if(ins.opcode== Opcode.CLC && insAfter?.opcode== Opcode.SEC) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
} }
@ -114,19 +114,19 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
val labelSymbol = ins.labelSymbol val labelSymbol = ins.labelSymbol
if(ins.opcode== Opcode.JUMP && labelSymbol!=null) { if(ins.opcode== Opcode.JUMP && labelSymbol!=null) {
// remove jump/branch to label immediately below // remove jump/branch to label immediately below
if(idx < chunk.lines.size-1) { if(idx < chunk.instructions.size-1) {
val label = chunk.lines[idx+1] as? IRCodeLabel val label = chunk.instructions[idx+1] as? IRCodeLabel
if(label?.name == labelSymbol) { if(label?.name == labelSymbol) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
} }
} }
// remove useless RETURN // remove useless RETURN
if(ins.opcode == Opcode.RETURN && idx>0) { 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)) { if(previous?.opcode in setOf(Opcode.JUMP, Opcode.JUMPA, Opcode.RETURN)) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
} }
@ -141,47 +141,47 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
when (ins.opcode) { when (ins.opcode) {
Opcode.DIV, Opcode.DIVS, Opcode.MUL, Opcode.MOD -> { Opcode.DIV, Opcode.DIVS, Opcode.MUL, Opcode.MOD -> {
if (ins.value == 1) { if (ins.value == 1) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
} }
Opcode.ADD, Opcode.SUB -> { Opcode.ADD, Opcode.SUB -> {
if (ins.value == 1) { if (ins.value == 1) {
chunk.lines[idx] = IRInstruction( chunk.instructions[idx] = IRInstruction(
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC, if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
ins.type, ins.type,
ins.reg1 ins.reg1
) )
changed = true changed = true
} else if (ins.value == 0) { } else if (ins.value == 0) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
} }
Opcode.AND -> { Opcode.AND -> {
if (ins.value == 0) { 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 changed = true
} else if (ins.value == 255 && ins.type == IRDataType.BYTE) { } else if (ins.value == 255 && ins.type == IRDataType.BYTE) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} else if (ins.value == 65535 && ins.type == IRDataType.WORD) { } else if (ins.value == 65535 && ins.type == IRDataType.WORD) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
} }
Opcode.OR -> { Opcode.OR -> {
if (ins.value == 0) { if (ins.value == 0) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} else if ((ins.value == 255 && ins.type == IRDataType.BYTE) || (ins.value == 65535 && ins.type == IRDataType.WORD)) { } 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 changed = true
} }
} }
Opcode.XOR -> { Opcode.XOR -> {
if (ins.value == 0) { if (ins.value == 0) {
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
changed = true changed = true
} }
} }
@ -196,7 +196,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
indexedInstructions.reversed().forEach { (idx, ins) -> indexedInstructions.reversed().forEach { (idx, ins) ->
if (ins.opcode == Opcode.NOP) { if (ins.opcode == Opcode.NOP) {
changed = true changed = true
chunk.lines.removeAt(idx) chunk.instructions.removeAt(idx)
} }
} }
return changed return changed

View File

@ -6,12 +6,12 @@ import prog8.codegen.intermediate.IRPeepholeOptimizer
import prog8.intermediate.* import prog8.intermediate.*
class TestIRPeepholeOpt: FunSpec({ 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 block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val sub = IRSubroutine("main.start", emptyList(), null, Position.DUMMY) val sub = IRSubroutine("main.start", emptyList(), null, Position.DUMMY)
val chunk = IRCodeChunk(Position.DUMMY) val chunk = IRCodeChunk(Position.DUMMY)
for(line in lines) for(instr in instructions)
chunk += line chunk += instr
sub += chunk sub += chunk
block += sub block += sub
val target = VMTarget() val target = VMTarget()
@ -30,7 +30,7 @@ class TestIRPeepholeOpt: FunSpec({
return prog 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") { test("remove nops") {
val irProg = makeIRProgram(listOf( val irProg = makeIRProgram(listOf(
@ -38,10 +38,10 @@ class TestIRPeepholeOpt: FunSpec({
IRInstruction(Opcode.NOP), IRInstruction(Opcode.NOP),
IRInstruction(Opcode.NOP) IRInstruction(Opcode.NOP)
)) ))
irProg.lines().size shouldBe 3 irProg.instructions().size shouldBe 3
val opt = IRPeepholeOptimizer(irProg) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
irProg.lines().size shouldBe 1 irProg.instructions().size shouldBe 1
} }
test("remove jmp to label below") { test("remove jmp to label below") {
@ -55,10 +55,10 @@ class TestIRPeepholeOpt: FunSpec({
IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1), IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1),
IRCodeLabel("label3") IRCodeLabel("label3")
)) ))
irProg.lines().size shouldBe 8 irProg.instructions().size shouldBe 8
val opt = IRPeepholeOptimizer(irProg) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
val lines = irProg.lines() val lines = irProg.instructions()
lines.size shouldBe 5 lines.size shouldBe 5
(lines[0] as IRCodeLabel).name shouldBe "label" (lines[0] as IRCodeLabel).name shouldBe "label"
(lines[1] as IRCodeLabel).name shouldBe "label2" (lines[1] as IRCodeLabel).name shouldBe "label2"
@ -76,10 +76,10 @@ class TestIRPeepholeOpt: FunSpec({
IRInstruction(Opcode.CLC), IRInstruction(Opcode.CLC),
IRInstruction(Opcode.CLC) IRInstruction(Opcode.CLC)
)) ))
irProg.lines().size shouldBe 6 irProg.instructions().size shouldBe 6
val opt = IRPeepholeOptimizer(irProg) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
val lines = irProg.lines() val lines = irProg.instructions()
lines.size shouldBe 1 lines.size shouldBe 1
(lines[0] as IRInstruction).opcode shouldBe Opcode.CLC (lines[0] as IRInstruction).opcode shouldBe Opcode.CLC
} }
@ -91,10 +91,10 @@ class TestIRPeepholeOpt: FunSpec({
IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=99), IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=99),
IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=222) IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=222)
)) ))
irProg.lines().size shouldBe 4 irProg.instructions().size shouldBe 4
val opt = IRPeepholeOptimizer(irProg) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
val lines = irProg.lines() val lines = irProg.instructions()
lines.size shouldBe 1 lines.size shouldBe 1
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOADR (lines[0] as IRInstruction).opcode shouldBe Opcode.LOADR
(lines[0] as IRInstruction).reg1 shouldBe 222 (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.ADD, IRDataType.BYTE, reg1=42, value = 0),
IRInstruction(Opcode.SUB, 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) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
val lines = irProg.lines() val lines = irProg.instructions()
lines.size shouldBe 4 lines.size shouldBe 4
} }
@ -126,10 +126,10 @@ class TestIRPeepholeOpt: FunSpec({
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 1), IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 1),
IRInstruction(Opcode.SUB, 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) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
val lines = irProg.lines() val lines = irProg.instructions()
lines.size shouldBe 2 lines.size shouldBe 2
(lines[0] as IRInstruction).opcode shouldBe Opcode.INC (lines[0] as IRInstruction).opcode shouldBe Opcode.INC
(lines[1] as IRInstruction).opcode shouldBe Opcode.DEC (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.OR, IRDataType.BYTE, reg1=42, value = 1),
IRInstruction(Opcode.XOR, 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) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
val lines = irProg.lines() val lines = irProg.instructions()
lines.size shouldBe 4 lines.size shouldBe 4
} }
@ -160,10 +160,10 @@ class TestIRPeepholeOpt: FunSpec({
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 255), IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 255),
IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, value = 65535) IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, value = 65535)
)) ))
irProg.lines().size shouldBe 4 irProg.instructions().size shouldBe 4
val opt = IRPeepholeOptimizer(irProg) val opt = IRPeepholeOptimizer(irProg)
opt.optimize() opt.optimize()
val lines = irProg.lines() val lines = irProg.instructions()
lines.size shouldBe 4 lines.size shouldBe 4
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOAD (lines[0] as IRInstruction).opcode shouldBe Opcode.LOAD
(lines[1] as IRInstruction).opcode shouldBe Opcode.LOAD (lines[1] as IRInstruction).opcode shouldBe Opcode.LOAD

View File

@ -3,6 +3,9 @@ TODO
For next release 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 - 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: 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: add more optimizations in IRPeepholeOptimizer
- ir: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us) - 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. - 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.

View File

@ -11,7 +11,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir")) private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
private val out = outfile.bufferedWriter() private val out = outfile.bufferedWriter()
private var numChunks = 0 private var numChunks = 0
private var numLines = 0 private var numInstr = 0
fun write(): Path { fun write(): Path {
@ -35,7 +35,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
val used = irProgram.registersUsed() val used = irProgram.registersUsed()
val numberUsed = (used.inputRegs.keys + used.outputRegs.keys).size + (used.inputFpRegs.keys + used.outputFpRegs.keys).size 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 return outfile
} }
@ -63,11 +63,11 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
is IRInlineBinaryChunk -> writeInlineBytes(chunk) is IRInlineBinaryChunk -> writeInlineBytes(chunk)
else -> { else -> {
out.write("<C>\n") out.write("<C>\n")
if (chunk.lines.isEmpty()) if (chunk.instructions.isEmpty())
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}") throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
chunk.lines.forEach { line -> chunk.instructions.forEach { instr ->
numLines++ numInstr++
out.writeLine(line) out.writeLine(instr)
} }
out.write("</C>\n") out.write("</C>\n")
} }

View File

@ -55,7 +55,7 @@ class IRProgram(val name: String,
val globalInits = mutableListOf<IRCodeLine>() val globalInits = mutableListOf<IRCodeLine>()
val blocks = mutableListOf<IRBlock>() val blocks = mutableListOf<IRBlock>()
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.lines) fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.instructions)
fun addBlock(block: IRBlock) { fun addBlock(block: IRBlock) {
require(blocks.all { it.name != block.name}) { "duplicate block ${block.name} ${block.position}" } require(blocks.all { it.name != block.name}) { "duplicate block ${block.name} ${block.position}" }
blocks.add(block) blocks.add(block)
@ -68,11 +68,11 @@ class IRProgram(val name: String,
fun validate() { fun validate() {
blocks.forEach { blocks.forEach {
it.inlineAssembly.forEach { chunk -> it.inlineAssembly.forEach { chunk ->
require(chunk.lines.isEmpty()) require(chunk.instructions.isEmpty())
} }
it.subroutines.forEach { sub -> it.subroutines.forEach { sub ->
sub.chunks.forEach { chunk -> 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() class IRCodeLabel(val name: String): IRCodeLine()
abstract class IRCodeChunkBase(val position: Position) { abstract class IRCodeChunkBase(val position: Position) {
val lines = mutableListOf<IRCodeLine>() val instructions = mutableListOf<IRCodeLine>()
abstract fun isEmpty(): Boolean abstract fun isEmpty(): Boolean
abstract fun isNotEmpty(): Boolean abstract fun isNotEmpty(): Boolean
@ -185,14 +185,14 @@ abstract class IRCodeChunkBase(val position: Position) {
class IRCodeChunk(position: Position): IRCodeChunkBase(position) { class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
override fun isEmpty() = lines.isEmpty() override fun isEmpty() = instructions.isEmpty()
override fun isNotEmpty() = lines.isNotEmpty() override fun isNotEmpty() = instructions.isNotEmpty()
override fun usedRegisters(): RegistersUsed { override fun usedRegisters(): RegistersUsed {
val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 } val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 } val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 } val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 } val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
lines.forEach { instructions.forEach {
if(it is IRInstruction) if(it is IRInstruction)
it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
} }
@ -200,11 +200,11 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
} }
operator fun plusAssign(line: IRCodeLine) { operator fun plusAssign(line: IRCodeLine) {
lines.add(line) instructions.add(line)
} }
operator fun plusAssign(chunk: IRCodeChunkBase) { operator fun plusAssign(chunk: IRCodeChunkBase) {
lines.addAll(chunk.lines) instructions.addAll(chunk.instructions)
} }
} }

View File

@ -39,7 +39,7 @@ class VmProgramLoader {
when (chunk) { when (chunk) {
is IRInlineAsmChunk -> addAssemblyToProgram(chunk, program, symbolAddresses) is IRInlineAsmChunk -> addAssemblyToProgram(chunk, program, symbolAddresses)
is IRInlineBinaryChunk -> program += IRInstruction(Opcode.BINARYDATA, binaryData = chunk.data) 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( private fun addToProgram(
lines: Iterable<IRCodeLine>, instructions: Iterable<IRCodeLine>,
program: MutableList<IRInstruction>, program: MutableList<IRInstruction>,
symbolAddresses: MutableMap<String, Int> symbolAddresses: MutableMap<String, Int>
) { ) {
lines.map { instructions.map {
when(it) { when(it) {
is IRInstruction -> { is IRInstruction -> {
it.labelSymbol?.let { symbol -> placeholders[program.size]=symbol } it.labelSymbol?.let { symbol -> placeholders[program.size]=symbol }

View File

@ -61,8 +61,8 @@ class TestVm: FunSpec( {
vm.memory.getUW(1000) shouldBe 12345u vm.memory.getUW(1000) shouldBe 12345u
vm.callStack.shouldBeEmpty() vm.callStack.shouldBeEmpty()
vm.valueStack.shouldBeEmpty() vm.valueStack.shouldBeEmpty()
vm.pc shouldBe code.lines.size-1 vm.pc shouldBe code.instructions.size-1
vm.stepCount shouldBe code.lines.size vm.stepCount shouldBe code.instructions.size
} }
test("vm asmsub not supported") { test("vm asmsub not supported") {