diff --git a/codeCore/src/prog8/code/ast/AstBase.kt b/codeCore/src/prog8/code/ast/AstBase.kt index 77c612dc8..fb665f6bb 100644 --- a/codeCore/src/prog8/code/ast/AstBase.kt +++ b/codeCore/src/prog8/code/ast/AstBase.kt @@ -42,7 +42,7 @@ class PtNodeGroup : PtNode(Position.DUMMY) { } -abstract class PtNamedNode(val name: String, position: Position): PtNode(position) { +sealed class PtNamedNode(val name: String, position: Position): PtNode(position) { val scopedName: List by lazy { var namedParent: PtNode = this.parent if(namedParent is PtProgram) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRChunkLinker.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRChunkLinker.kt deleted file mode 100644 index 1e5be9c25..000000000 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRChunkLinker.kt +++ /dev/null @@ -1,43 +0,0 @@ -package prog8.codegen.intermediate - -import prog8.code.core.AssemblyError -import prog8.intermediate.* - -internal class IRChunkLinker(private val irprog: IRProgram) { - - private val labeledChunks = irprog.blocks.flatMap { it.subroutines }.flatMap { it.chunks }.associateBy { it.label } - - fun link() { - - irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub -> - sub.chunks.withIndex().forEach { (index, chunk) -> - - if(chunk is IRCodeChunk) { - // link sequential chunks - val jump = chunk.instructions.lastOrNull()?.opcode - if (jump == null || jump !in setOf(Opcode.JUMP, Opcode.JUMPA, Opcode.RETURN)) { - // no jump at the end, so link to next chunk (if it exists) - if(index + if(block.inlineAssembly.isNotEmpty()) { + val first = block.inlineAssembly.first() + if(first.label==null) { + val replacement = IRInlineAsmChunk(block.name, first.assembly, first.isIR, first.position) + block.inlineAssembly.removeAt(0) + block.inlineAssembly.add(0, replacement) + } else if(first.label != block.name) { + throw AssemblyError("first chunk in block has label that differs from block name") + } + } + + block.subroutines.forEach { sub -> + if(sub.chunks.isNotEmpty()) { + val first = sub.chunks.first() + if(first.label==null) { + val replacement = when(first) { + is IRCodeChunk -> { + val replacement = IRCodeChunk(sub.name, first.position, first.next) + replacement.instructions += first.instructions + replacement + } + is IRInlineAsmChunk -> IRInlineAsmChunk(sub.name, first.assembly, first.isIR, first.position) + is IRInlineBinaryChunk -> IRInlineBinaryChunk(sub.name, first.data, first.position) + else -> throw AssemblyError("invalid chunk") + } + sub.chunks.removeAt(0) + sub.chunks.add(0, replacement) + } else if(first.label != sub.name) { + val next = if(first is IRCodeChunk) first else null + sub.chunks.add(0, IRCodeChunk(sub.name, sub.position, next)) + } + } + } + } + } + private fun replaceMemoryMappedVars(irProg: IRProgram) { // replace memory mapped variable symbols with the memory address directly. // note: we do still export the memory mapped symbols so a code generator can use those @@ -309,7 +349,7 @@ class IRCodeGen( val labeledFirstChunk = when(val first=chunks[0]) { is IRCodeChunk -> { val newChunk = IRCodeChunk(label, first.position, null) - first.instructions.forEach { newChunk += it } + newChunk.instructions += first.instructions newChunk } is IRInlineAsmChunk -> { diff --git a/codeGenIntermediate/test/TestIRPeepholeOpt.kt b/codeGenIntermediate/test/TestIRPeepholeOpt.kt index 10eb809ec..1defde54e 100644 --- a/codeGenIntermediate/test/TestIRPeepholeOpt.kt +++ b/codeGenIntermediate/test/TestIRPeepholeOpt.kt @@ -2,7 +2,6 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import prog8.code.core.* import prog8.code.target.VMTarget -import prog8.codegen.intermediate.IRChunkLinker import prog8.codegen.intermediate.IRPeepholeOptimizer import prog8.intermediate.* @@ -25,6 +24,7 @@ class TestIRPeepholeOpt: FunSpec({ ) val prog = IRProgram("test", IRSymbolTable(null), options, target) prog.addBlock(block) + prog.linkChunks() prog.validate() return prog } @@ -44,7 +44,6 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.NOP) )) irProg.chunks().single().instructions.size shouldBe 3 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() irProg.chunks().single().instructions.size shouldBe 1 @@ -64,7 +63,6 @@ class TestIRPeepholeOpt: FunSpec({ irProg.chunks().size shouldBe 4 irProg.chunks().flatMap { it.instructions }.size shouldBe 5 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() irProg.chunks().size shouldBe 3 @@ -87,7 +85,6 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.CLC) )) irProg.chunks().single().instructions.size shouldBe 6 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() val instr = irProg.chunks().single().instructions @@ -103,7 +100,6 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=222) )) irProg.chunks().single().instructions.size shouldBe 4 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() val instr = irProg.chunks().single().instructions @@ -127,7 +123,6 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 0) )) irProg.chunks().single().instructions.size shouldBe 10 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() irProg.chunks().single().instructions.size shouldBe 4 @@ -139,7 +134,6 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 1) )) irProg.chunks().single().instructions.size shouldBe 2 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() val instr = irProg.chunks().single().instructions @@ -160,7 +154,6 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.XOR, IRDataType.BYTE, reg1=42, value = 1) )) irProg.chunks().single().instructions.size shouldBe 8 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() irProg.chunks().single().instructions.size shouldBe 4 @@ -174,7 +167,6 @@ class TestIRPeepholeOpt: FunSpec({ IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, value = 65535) )) irProg.chunks().single().instructions.size shouldBe 4 - IRChunkLinker(irProg).link() val opt = IRPeepholeOptimizer(irProg) opt.optimize() val instr = irProg.chunks().single().instructions diff --git a/docs/source/todo.rst b/docs/source/todo.rst index cc0b63fc9..c538e3e3b 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,13 +3,13 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- ir: check that block and sub labels are also on the first chunk in said block/sub -- ir: link all sequential chunks to another (exiting one chunk 'calls' the next chunk) +- vm: program is list of chunks, fix dispatcher +- ir: see TODO replace IM syscalls by their VM Syscall equivalent - ir: fix JUMP, RETURN and all branching instructions to reference a chunk + index instead of just a single programcounter index - ir: fix removeWeirdBranches in IR optimizer - ir: fix unit tests -- ir: fix joinChunks() in the IR optimizer -- vm: program is list of chunks, fix dispatcher +- ir: fix joinChunks() in the IR optimizer - there are WAY too many chunks with 1 instruction in them only +- ir: next in IRCodeChunk can also be a Asm Chunk which can have next as well - add cx16diskio.vload_raw() to load headerless files into vram ... diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 70d0eb46b..3417d42a8 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -44,6 +44,7 @@ class IRFileReader { program.addGlobalInits(initGlobals) blocks.forEach{ program.addBlock(it) } + program.linkChunks() program.validate() return program } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index a92f11ba8..0f653c39f 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -25,10 +25,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { out.write("\n\n") if(!irProgram.options.dontReinitGlobals) { - out.write("\n") // note: this a block of code that loads values and stores them into the global variables to reset their values. - irProgram.globalInits.forEach { out.write(it.toString()) } - out.write("\n") + writeCodeChunk(irProgram.globalInits) } out.write("\n") writeBlocks() @@ -63,18 +61,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { when (chunk) { is IRInlineAsmChunk -> writeInlineAsm(chunk) is IRInlineBinaryChunk -> writeInlineBytes(chunk) - else -> { - if(chunk.label!=null) - out.write("\n") - else - out.write("\n") - chunk.instructions.forEach { instr -> - numInstr++ - out.write(instr.toString()) - out.write("\n") - } - out.write("\n") - } + is IRCodeChunk -> writeCodeChunk(chunk) + else -> throw InternalCompilerException("invalid chunk") } } out.write("\n") @@ -101,6 +89,19 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { } } + private fun writeCodeChunk(chunk: IRCodeChunk) { + if(chunk.label!=null) + out.write("\n") + else + out.write("\n") + chunk.instructions.forEach { instr -> + numInstr++ + out.write(instr.toString()) + out.write("\n") + } + out.write("\n") + } + private fun writeInlineBytes(chunk: IRInlineBinaryChunk) { out.write("\n") chunk.data.withIndex().forEach {(index, byte) -> diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index 1fc704100..dbb500495 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -353,60 +353,6 @@ enum class Opcode { BINARYDATA } -val OpcodesWithAddress = setOf( - Opcode.LOADM, - Opcode.LOADX, - Opcode.LOADIX, - Opcode.STOREM, - Opcode.STOREX, - Opcode.STOREIX, - Opcode.STOREZM, - Opcode.STOREZX, - Opcode.JUMP, - Opcode.JUMPA, - Opcode.CALL, - Opcode.INCM, - Opcode.DECM, - Opcode.NEGM, - Opcode.ADDM, - Opcode.SUBM, - Opcode.MULM, - Opcode.DIVM, - Opcode.DIVSM, - Opcode.INVM, - Opcode.ORM, - Opcode.XORM, - Opcode.ANDM, - Opcode.ASRM, - Opcode.LSRM, - Opcode.LSLM, - Opcode.LSLNM, - Opcode.LSRNM, - Opcode.ASRNM, - Opcode.ROLM, - Opcode.RORM, - Opcode.ROXLM, - Opcode.ROXRM, - Opcode.BSTCC, - Opcode.BSTCS, - Opcode.BSTEQ, - Opcode.BSTNE, - Opcode.BSTNEG, - Opcode.BSTPOS, - Opcode.BZ, - Opcode.BNZ, - Opcode.BEQ, - Opcode.BNE, - Opcode.BLT, - Opcode.BLTS, - Opcode.BLE, - Opcode.BLES, - Opcode.BGT, - Opcode.BGTS, - Opcode.BGE, - Opcode.BGES -) - val OpcodesThatBranch = setOf( Opcode.JUMP, Opcode.JUMPA, @@ -681,7 +627,7 @@ data class IRInstruction( require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"} require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"} require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"} - if(value!=null && opcode !in OpcodesWithAddress) { + if(value!=null) { when (type) { IRDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"} IRDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"} diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index 06ca249b6..92cf6ff80 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -52,10 +52,13 @@ class IRProgram(val name: String, val encoding: IStringEncoding) { val asmSymbols = mutableMapOf() - val globalInits = mutableListOf() + val globalInits = IRCodeChunk(null, Position.DUMMY, null) val blocks = mutableListOf() - fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.instructions) + fun addGlobalInits(chunk: IRCodeChunk) { + globalInits += chunk + } + fun addBlock(block: IRBlock) { require(blocks.all { it.name != block.name}) { "duplicate block ${block.name} ${block.position}" } blocks.add(block) @@ -65,15 +68,84 @@ class IRProgram(val name: String, asmSymbols += symbolDefs } + fun linkChunks() { + val labeledChunks = blocks.flatMap { it.subroutines }.flatMap { it.chunks }.associateBy { it.label } + + if(globalInits.isNotEmpty()) { + if(globalInits.next==null) { + val firstBlock = blocks.firstOrNull() + if(firstBlock!=null) { + if(firstBlock.inlineAssembly.isNotEmpty()) { + TODO("link to inline assembly block") + // irprog.globalInits.next = firstBlock.inlineAssembly.first() + } else if(firstBlock.subroutines.isNotEmpty()) { + val firstSub = firstBlock.subroutines.first() + if(firstSub.chunks.isNotEmpty()) { + val firstChunk = firstSub.chunks.first() + when(firstChunk) { + is IRCodeChunk -> globalInits.next = firstChunk + else -> TODO("link to other type of chunk") + } + } + } + } + } + } + + blocks.asSequence().flatMap { it.subroutines }.forEach { sub -> + sub.chunks.withIndex().forEach { (index, chunk) -> + + when (chunk) { + is IRCodeChunk -> { + // link sequential chunks + val jump = chunk.instructions.lastOrNull()?.opcode + if (jump == null || jump !in setOf(Opcode.JUMP, Opcode.JUMPA, Opcode.RETURN)) { + // no jump at the end, so link to next chunk (if it exists) + if(index { + // TODO("link next of asm chunk") + } + is IRInlineBinaryChunk -> { + // TODO("link next of binary chunk") + } + else -> throw AssemblyError("invalid chunk") + } + } + } + } + fun validate() { - - // TODO: check that block and sub labels are also on the first chunk in said block/sub - - blocks.forEach { - it.inlineAssembly.forEach { chunk -> + blocks.forEach { block -> + if(block.inlineAssembly.isNotEmpty()) { + require(block.inlineAssembly.first().label == block.name) { "first block chunk should have block name as its label" } + } + block.inlineAssembly.forEach { chunk -> require(chunk.instructions.isEmpty()) } - it.subroutines.forEach { sub -> + block.subroutines.forEach { sub -> + if(sub.chunks.isNotEmpty()) { + require(sub.chunks.first().label == sub.name) { "first chunk in subroutine should have sub name as its label" } + } sub.chunks.forEach { chunk -> if (chunk is IRCodeChunk) require(chunk.instructions.isNotEmpty() || chunk.label!=null) else require(chunk.instructions.isEmpty()) @@ -95,7 +167,7 @@ class IRProgram(val name: String, usedRegisters.outputFpRegs.forEach{ (reg, count) -> outputFpRegs[reg] = outputFpRegs.getValue(reg) + count } } - globalInits.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) } + globalInits.instructions.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) } blocks.forEach { it.inlineAssembly.forEach { chunk -> addUsed(chunk.usedRegisters()) } it.subroutines.flatMap { sub->sub.chunks }.forEach { chunk -> addUsed(chunk.usedRegisters()) } @@ -112,9 +184,9 @@ class IRBlock( val alignment: BlockAlignment, val position: Position ) { + val inlineAssembly = mutableListOf() val subroutines = mutableListOf() val asmSubroutines = mutableListOf() - val inlineAssembly = mutableListOf() enum class BlockAlignment { NONE, @@ -177,7 +249,7 @@ class IRAsmSubroutine( fun usedRegisters() = registersUsed } -abstract class IRCodeChunkBase(val label: String?, val position: Position) { +sealed class IRCodeChunkBase(val label: String?, val position: Position) { val instructions = mutableListOf() abstract fun isEmpty(): Boolean @@ -187,7 +259,7 @@ abstract class IRCodeChunkBase(val label: String?, val position: Position) { class IRCodeChunk(label: String?, position: Position, - var next: IRCodeChunk?): IRCodeChunkBase(label, position) { + var next: IRCodeChunk?): IRCodeChunkBase(label, position) { // TODO next can also be InlineAsmChunk!! which can also have a next again. override fun isEmpty() = instructions.isEmpty() override fun isNotEmpty() = instructions.isNotEmpty() diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index 5c01bbd3b..4a8f6bf91 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -206,7 +206,7 @@ fun parseIRCodeLine(line: String, location: Pair?, placeholder throw IRParseException("invalid reg1 for $line") if(format.reg2==OperandDirection.UNUSED && reg2!=null) throw IRParseException("invalid reg2 for $line") - if(value!=null && opcode !in OpcodesWithAddress) { + if(value!=null) { when (type) { IRDataType.BYTE -> { if (value < -128 || value > 255) diff --git a/intermediate/test/TestIRFileInOut.kt b/intermediate/test/TestIRFileInOut.kt index 575fc1739..6d16f49f5 100644 --- a/intermediate/test/TestIRFileInOut.kt +++ b/intermediate/test/TestIRFileInOut.kt @@ -75,7 +75,7 @@ load.b r1,42 - + return @@ -86,7 +86,7 @@ return uword sys.wait.jiffies - + loadm.w r0,sys.wait.jiffies syscall 13 diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 14f92d870..81fc311b3 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -117,10 +117,12 @@ class VirtualMachine(irProgram: IRProgram) { } } - private inline fun nextPc() { + private fun nextPc() { pcIndex ++ if(pcIndex>=pcChunk.instructions.size) { pcIndex = 0 + if(pcChunk.next==null) + TODO("huh no next chunk in $pcChunk") pcChunk = pcChunk.next!! } } diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 587f7029a..bdbe6a329 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -1,5 +1,6 @@ package prog8.vm +import prog8.code.core.AssemblyError import prog8.code.core.DataType import prog8.code.core.Position import prog8.intermediate.* @@ -11,14 +12,14 @@ class VmProgramLoader { placeholders.clear() irProgram.validate() val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget) - val symbolAddresses = allocations.allocations.toMutableMap() + val variableAddresses = allocations.allocations.toMutableMap() val programChunks = mutableListOf() - varsToMemory(irProgram, allocations, symbolAddresses, memory) + varsToMemory(irProgram, allocations, variableAddresses, memory) if(!irProgram.options.dontReinitGlobals) { if(irProgram.globalInits.isNotEmpty()) - addToProgram(irProgram.globalInits, programChunks, symbolAddresses) + programChunks += irProgram.globalInits } // make sure that if there is a "main.start" entrypoint, we jump to it @@ -31,18 +32,19 @@ class VmProgramLoader { } } - // TODO load rest of the program + // load rest of the program into the list irProgram.blocks.forEach { block -> if(block.address!=null) throw IRParseException("blocks cannot have a load address for vm: ${block.name}") - block.inlineAssembly.forEach { addAssemblyToProgram(it, programChunks, symbolAddresses) } + block.inlineAssembly.forEach { addAssemblyToProgram(it, programChunks, variableAddresses) } block.subroutines.forEach { it.chunks.forEach { chunk -> when (chunk) { - is IRInlineAsmChunk -> addAssemblyToProgram(chunk, programChunks, symbolAddresses) + is IRInlineAsmChunk -> addAssemblyToProgram(chunk, programChunks, variableAddresses) is IRInlineBinaryChunk -> TODO("inline binary data not yet supported in the VM") - else -> addToProgram(chunk.instructions, programChunks, symbolAddresses) + is IRCodeChunk -> programChunks += chunk + else -> throw AssemblyError("weird chunk type") } } } @@ -50,33 +52,34 @@ class VmProgramLoader { throw IRParseException("vm currently does not support asmsubs: ${block.asmSubroutines.first().name}") } - pass2replaceLabelsByProgIndex(programChunks, symbolAddresses) - - programChunks.asSequence().flatMap { it.instructions }.forEach { - if(it.opcode in OpcodesWithAddress && it.value==null) { - throw IRParseException("instruction missing numeric value, label not replaced? $it") - } - } + pass2replaceLabelsByProgIndex(programChunks, variableAddresses) return programChunks } private fun pass2replaceLabelsByProgIndex( chunks: MutableList, - symbolAddresses: MutableMap + variableAddresses: MutableMap ) { for((ref, label) in placeholders) { val (chunk, line) = ref - val replacement = symbolAddresses[label] + val replacement = variableAddresses[label] if(replacement==null) { // it could be an address + index: symbol+42 if('+' in label) { val (symbol, indexStr) = label.split('+') val index = indexStr.toInt() - val address = symbolAddresses.getValue(symbol) + index + val address = variableAddresses.getValue(symbol) + index chunk.instructions[line] = chunk.instructions[line].copy(value = address) } else { - throw IRParseException("placeholder not found in labels: $label") + // placeholder is not a variable, so it must be a label of a code chunk instead + val target: IRCodeChunk? = chunks.firstOrNull { it.label==label } + if(target==null) + throw IRParseException("placeholder not found in variables nor labels: $label") + else { + require(chunk.instructions[line].opcode in OpcodesThatBranch) + chunk.instructions[line] = chunk.instructions[line].copy(branchTarget = target, value = null) + } } } else { chunk.instructions[line] = chunk.instructions[line].copy(value = replacement) @@ -84,39 +87,39 @@ class VmProgramLoader { } } - private fun addToProgram( - instructions: Iterable, - program: MutableList, - symbolAddresses: MutableMap - ) { - val chunk = IRCodeChunk(null, Position.DUMMY, null) - instructions.map { - it.labelSymbol?.let { symbol -> placeholders[Pair(chunk, chunk.instructions.size)]=symbol } - if(it.opcode==Opcode.SYSCALL) { - // convert IR Syscall to VM Syscall - val vmSyscall = when(it.value!!) { - IMSyscall.SORT_UBYTE.ordinal -> Syscall.SORT_UBYTE - IMSyscall.SORT_BYTE.ordinal -> Syscall.SORT_BYTE - IMSyscall.SORT_UWORD.ordinal -> Syscall.SORT_UWORD - IMSyscall.SORT_WORD.ordinal -> Syscall.SORT_WORD - IMSyscall.ANY_BYTE.ordinal -> Syscall.ANY_BYTE - IMSyscall.ANY_WORD.ordinal -> Syscall.ANY_WORD - IMSyscall.ANY_FLOAT.ordinal -> Syscall.ANY_FLOAT - IMSyscall.ALL_BYTE.ordinal -> Syscall.ALL_BYTE - IMSyscall.ALL_WORD.ordinal -> Syscall.ALL_WORD - IMSyscall.ALL_FLOAT.ordinal -> Syscall.ALL_FLOAT - IMSyscall.REVERSE_BYTES.ordinal -> Syscall.REVERSE_BYTES - IMSyscall.REVERSE_WORDS.ordinal -> Syscall.REVERSE_WORDS - IMSyscall.REVERSE_FLOATS.ordinal -> Syscall.REVERSE_FLOATS - else -> throw IRParseException("invalid IM syscall number $it") - } - chunk += it.copy(value=vmSyscall.ordinal) - } else { - chunk += it - } - } - program += chunk - } + // TODO replace IM syscalls by their VM Syscall equivalent +// private fun addToProgram( +// instructions: Iterable, +// program: MutableList +// ) { +// val chunk = IRCodeChunk(null, Position.DUMMY, null) +// instructions.map { +// it.labelSymbol?.let { symbol -> placeholders[Pair(chunk, chunk.instructions.size)]=symbol } +// if(it.opcode==Opcode.SYSCALL) { +// // convert IR Syscall to VM Syscall +// val vmSyscall = when(it.value!!) { +// IMSyscall.SORT_UBYTE.ordinal -> Syscall.SORT_UBYTE +// IMSyscall.SORT_BYTE.ordinal -> Syscall.SORT_BYTE +// IMSyscall.SORT_UWORD.ordinal -> Syscall.SORT_UWORD +// IMSyscall.SORT_WORD.ordinal -> Syscall.SORT_WORD +// IMSyscall.ANY_BYTE.ordinal -> Syscall.ANY_BYTE +// IMSyscall.ANY_WORD.ordinal -> Syscall.ANY_WORD +// IMSyscall.ANY_FLOAT.ordinal -> Syscall.ANY_FLOAT +// IMSyscall.ALL_BYTE.ordinal -> Syscall.ALL_BYTE +// IMSyscall.ALL_WORD.ordinal -> Syscall.ALL_WORD +// IMSyscall.ALL_FLOAT.ordinal -> Syscall.ALL_FLOAT +// IMSyscall.REVERSE_BYTES.ordinal -> Syscall.REVERSE_BYTES +// IMSyscall.REVERSE_WORDS.ordinal -> Syscall.REVERSE_WORDS +// IMSyscall.REVERSE_FLOATS.ordinal -> Syscall.REVERSE_FLOATS +// else -> throw IRParseException("invalid IM syscall number $it") +// } +// chunk += it.copy(value=vmSyscall.ordinal) +// } else { +// chunk += it +// } +// } +// program += chunk +// } private fun varsToMemory( program: IRProgram,