mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
fixed vm problem with branching instructions in global init chunk
This commit is contained in:
parent
4db4a5f1b2
commit
de3d0b40dc
@ -148,6 +148,7 @@ class IRUnusedCodeRemover(
|
|||||||
val entrypointSub = irprog.blocks.single { it.label=="main" }
|
val entrypointSub = irprog.blocks.single { it.label=="main" }
|
||||||
.children.single { it is IRSubroutine && it.label=="main.start" }
|
.children.single { it is IRSubroutine && it.label=="main.start" }
|
||||||
val reachable = mutableSetOf((entrypointSub as IRSubroutine).chunks.first())
|
val reachable = mutableSetOf((entrypointSub as IRSubroutine).chunks.first())
|
||||||
|
reachable.add(irprog.globalInits)
|
||||||
|
|
||||||
// all chunks referenced in array initializer values are also 'reachable':
|
// all chunks referenced in array initializer values are also 'reachable':
|
||||||
irprog.st.allVariables()
|
irprog.st.allVariables()
|
||||||
@ -230,6 +231,7 @@ class IRUnusedCodeRemover(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkedChunks.add(irprog.globalInits)
|
||||||
return removeUnlinkedChunks(linkedChunks)
|
return removeUnlinkedChunks(linkedChunks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,25 @@ class TestOptimization: FunSpec({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("don't remove empty subroutine if it's referenced in vardecl") {
|
||||||
|
val sourcecode = """
|
||||||
|
main {
|
||||||
|
ubyte tw = other.width()
|
||||||
|
sub start() {
|
||||||
|
tw++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
other {
|
||||||
|
sub width() -> ubyte {
|
||||||
|
cx16.r0++
|
||||||
|
return 80
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
compileText(C64Target(), true, sourcecode, writeAssembly = true) shouldNotBe null
|
||||||
|
compileText(VMTarget(), true, sourcecode, writeAssembly = true) shouldNotBe null
|
||||||
|
}
|
||||||
|
|
||||||
test("generated constvalue from typecast inherits proper parent linkage") {
|
test("generated constvalue from typecast inherits proper parent linkage") {
|
||||||
val number = NumericLiteral(DataType.UBYTE, 11.0, Position.DUMMY)
|
val number = NumericLiteral(DataType.UBYTE, 11.0, Position.DUMMY)
|
||||||
val tc = TypecastExpression(number, DataType.BYTE, false, Position.DUMMY)
|
val tc = TypecastExpression(number, DataType.BYTE, false, Position.DUMMY)
|
||||||
|
@ -59,10 +59,11 @@ main {
|
|||||||
VmRunner().runProgram(virtfile.readText())
|
VmRunner().runProgram(virtfile.readText())
|
||||||
}
|
}
|
||||||
|
|
||||||
test("compile virtual: str args and return type") {
|
test("compile virtual: str args and return type, and global var init") {
|
||||||
val src = """
|
val src = """
|
||||||
main {
|
main {
|
||||||
|
ubyte @shared dvar = test.dummy()
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
sub testsub(str s1) -> str {
|
sub testsub(str s1) -> str {
|
||||||
return "result"
|
return "result"
|
||||||
@ -70,6 +71,13 @@ main {
|
|||||||
|
|
||||||
uword result = testsub("arg")
|
uword result = testsub("arg")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
sub dummy() -> ubyte {
|
||||||
|
cx16.r0++
|
||||||
|
return 80
|
||||||
|
}
|
||||||
}"""
|
}"""
|
||||||
val target = VMTarget()
|
val target = VMTarget()
|
||||||
var result = compileText(target, false, src, writeAssembly = true)!!
|
var result = compileText(target, false, src, writeAssembly = true)!!
|
||||||
@ -467,4 +475,6 @@ main {
|
|||||||
compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null
|
compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
@ -69,10 +69,11 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
override fun visit(functionCallExpr: FunctionCallExpression) {
|
override fun visit(functionCallExpr: FunctionCallExpression) {
|
||||||
val otherSub = functionCallExpr.target.targetSubroutine(program)
|
val otherSub = functionCallExpr.target.targetSubroutine(program)
|
||||||
if (otherSub != null) {
|
if (otherSub != null) {
|
||||||
functionCallExpr.definingSubroutine?.let { thisSub ->
|
val definingSub = functionCallExpr.definingSubroutine
|
||||||
calls[thisSub] = calls.getValue(thisSub) + otherSub
|
if(definingSub!=null) {
|
||||||
calledBy[otherSub] = calledBy.getValue(otherSub) + functionCallExpr
|
calls[definingSub] = calls.getValue(definingSub) + otherSub
|
||||||
}
|
}
|
||||||
|
calledBy[otherSub] = calledBy.getValue(otherSub) + functionCallExpr
|
||||||
}
|
}
|
||||||
super.visit(functionCallExpr)
|
super.visit(functionCallExpr)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
fix ubyte width = text.width() text.width() gets removed as 'unused subroutine'
|
|
||||||
|
|
||||||
vm textelite: after 1 galaxy jump: galaxy maps shows wrong planet name until you redraw them a second time. Current planet name changes when showing maps and asking planet i)nfo!
|
vm textelite: after 1 galaxy jump: galaxy maps shows wrong planet name until you redraw them a second time. Current planet name changes when showing maps and asking planet i)nfo!
|
||||||
|
|
||||||
...
|
...
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
main {
|
main {
|
||||||
ubyte tw = text.width()
|
ubyte tw = other.width()
|
||||||
sub start() {
|
sub start() {
|
||||||
tw++
|
tw++
|
||||||
|
txt.print_uw(tw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text {
|
other {
|
||||||
sub width() -> ubyte {
|
sub width() -> ubyte {
|
||||||
cx16.r0++
|
cx16.r0++
|
||||||
return 80
|
return 80
|
||||||
|
@ -57,7 +57,10 @@ class IRProgram(val name: String,
|
|||||||
|
|
||||||
fun allSubs(): Sequence<IRSubroutine> = blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }
|
fun allSubs(): Sequence<IRSubroutine> = blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }
|
||||||
fun foreachSub(operation: (sub: IRSubroutine) -> Unit) = allSubs().forEach { operation(it) }
|
fun foreachSub(operation: (sub: IRSubroutine) -> Unit) = allSubs().forEach { operation(it) }
|
||||||
fun foreachCodeChunk(operation: (chunk: IRCodeChunkBase) -> Unit) = allSubs().flatMap { it.chunks }.forEach { operation(it) }
|
fun foreachCodeChunk(operation: (chunk: IRCodeChunkBase) -> Unit) {
|
||||||
|
allSubs().flatMap { it.chunks }.forEach { operation(it) }
|
||||||
|
operation(globalInits)
|
||||||
|
}
|
||||||
fun getChunkWithLabel(label: String): IRCodeChunkBase {
|
fun getChunkWithLabel(label: String): IRCodeChunkBase {
|
||||||
for(sub in allSubs()) {
|
for(sub in allSubs()) {
|
||||||
for(chunk in sub.chunks) {
|
for(chunk in sub.chunks) {
|
||||||
@ -123,44 +126,46 @@ class IRProgram(val name: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun linkCodeChunk(chunk: IRCodeChunk, next: IRCodeChunkBase?) {
|
||||||
|
// link sequential chunks
|
||||||
|
val jump = chunk.instructions.lastOrNull()?.opcode
|
||||||
|
if (jump == null || jump !in OpcodesThatJump) {
|
||||||
|
// no jump at the end, so link to next chunk (if it exists)
|
||||||
|
if(next!=null) {
|
||||||
|
if (next is IRCodeChunk && chunk.instructions.lastOrNull()?.opcode !in OpcodesThatJump)
|
||||||
|
chunk.next = next
|
||||||
|
else if(next is IRInlineAsmChunk)
|
||||||
|
chunk.next = next
|
||||||
|
else if(next is IRInlineBinaryChunk)
|
||||||
|
chunk.next =next
|
||||||
|
else
|
||||||
|
throw AssemblyError("code chunk followed by invalid chunk type $next")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// link all jump and branching instructions to their target
|
||||||
|
chunk.instructions.forEach {
|
||||||
|
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.JUMPI && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNR && it.labelSymbol!=null) {
|
||||||
|
if(it.labelSymbol.startsWith('$') || it.labelSymbol.first().isDigit()) {
|
||||||
|
// it's a call to an address (romsub most likely)
|
||||||
|
require(it.address!=null)
|
||||||
|
} else {
|
||||||
|
it.branchTarget = labeledChunks.getValue(it.labelSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun linkSubroutineChunks(sub: IRSubroutine) {
|
fun linkSubroutineChunks(sub: IRSubroutine) {
|
||||||
sub.chunks.withIndex().forEach { (index, chunk) ->
|
sub.chunks.withIndex().forEach { (index, chunk) ->
|
||||||
|
|
||||||
fun nextChunk(): IRCodeChunkBase? = if(index<sub.chunks.size-1) sub.chunks[index + 1] else null
|
val next = if(index<sub.chunks.size-1) sub.chunks[index + 1] else null
|
||||||
|
|
||||||
when (chunk) {
|
when (chunk) {
|
||||||
is IRCodeChunk -> {
|
is IRCodeChunk -> {
|
||||||
// link sequential chunks
|
linkCodeChunk(chunk, next)
|
||||||
val jump = chunk.instructions.lastOrNull()?.opcode
|
|
||||||
if (jump == null || jump !in OpcodesThatJump) {
|
|
||||||
// no jump at the end, so link to next chunk (if it exists)
|
|
||||||
val next = nextChunk()
|
|
||||||
if(next!=null) {
|
|
||||||
if (next is IRCodeChunk && chunk.instructions.lastOrNull()?.opcode !in OpcodesThatJump)
|
|
||||||
chunk.next = next
|
|
||||||
else if(next is IRInlineAsmChunk)
|
|
||||||
chunk.next = next
|
|
||||||
else if(next is IRInlineBinaryChunk)
|
|
||||||
chunk.next =next
|
|
||||||
else
|
|
||||||
throw AssemblyError("code chunk followed by invalid chunk type $next")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// link all jump and branching instructions to their target
|
|
||||||
chunk.instructions.forEach {
|
|
||||||
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.JUMPI && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNR && it.labelSymbol!=null) {
|
|
||||||
if(it.labelSymbol.startsWith('$') || it.labelSymbol.first().isDigit()) {
|
|
||||||
// it's a call to an address (romsub most likely)
|
|
||||||
require(it.address!=null)
|
|
||||||
} else {
|
|
||||||
it.branchTarget = labeledChunks.getValue(it.labelSymbol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is IRInlineAsmChunk -> {
|
is IRInlineAsmChunk -> {
|
||||||
val next = nextChunk()
|
|
||||||
if(next!=null) {
|
if(next!=null) {
|
||||||
val lastInstr = chunk.instructions.lastOrNull()
|
val lastInstr = chunk.instructions.lastOrNull()
|
||||||
if(lastInstr==null || lastInstr.opcode !in OpcodesThatJump)
|
if(lastInstr==null || lastInstr.opcode !in OpcodesThatJump)
|
||||||
@ -184,9 +189,64 @@ class IRProgram(val name: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
linkCodeChunk(globalInits, globalInits.next)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validate() {
|
fun validate() {
|
||||||
|
fun validateChunk(chunk: IRCodeChunkBase, sub: IRSubroutine?, emptyChunkIsAllowed: Boolean) {
|
||||||
|
if (chunk is IRCodeChunk) {
|
||||||
|
if(!emptyChunkIsAllowed)
|
||||||
|
require(chunk.instructions.isNotEmpty() || chunk.label != null)
|
||||||
|
if(chunk.instructions.lastOrNull()?.opcode in OpcodesThatJump)
|
||||||
|
require(chunk.next == null) { "chunk ending with a jump or return shouldn't be linked to next" }
|
||||||
|
else if (sub!=null) {
|
||||||
|
// if chunk is NOT the last in the block, it needs to link to next.
|
||||||
|
val isLast = sub.chunks.last() === chunk
|
||||||
|
require(isLast || chunk.next != null) { "chunk needs to be linked to next" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
require(chunk.instructions.isEmpty())
|
||||||
|
if(chunk is IRInlineAsmChunk)
|
||||||
|
require(!chunk.isIR) { "inline IR-asm should have been converted into regular code chunk"}
|
||||||
|
}
|
||||||
|
chunk.instructions.withIndex().forEach { (index, instr) ->
|
||||||
|
if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) {
|
||||||
|
if(instr.opcode==Opcode.JUMPI) {
|
||||||
|
val pointervar = st.lookup(instr.labelSymbol)!!
|
||||||
|
when(pointervar) {
|
||||||
|
is IRStStaticVariable -> require(pointervar.dt==DataType.UWORD)
|
||||||
|
is IRStMemVar -> require(pointervar.dt==DataType.UWORD)
|
||||||
|
else -> throw AssemblyError("weird pointervar type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!instr.labelSymbol.startsWith('$') && !instr.labelSymbol.first().isDigit())
|
||||||
|
require(instr.branchTarget != null) { "branching instruction to label should have branchTarget set" }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(instr.opcode==Opcode.PREPARECALL) {
|
||||||
|
var i = index+1
|
||||||
|
var instr2 = chunk.instructions[i]
|
||||||
|
val registers = mutableSetOf<Int>()
|
||||||
|
while(instr2.opcode!=Opcode.SYSCALL && instr2.opcode!=Opcode.CALL && i<chunk.instructions.size-1) {
|
||||||
|
if(instr2.reg1direction==OperandDirection.WRITE || instr2.reg1direction==OperandDirection.READWRITE) registers.add(instr2.reg1!!)
|
||||||
|
if(instr2.reg2direction==OperandDirection.WRITE || instr2.reg2direction==OperandDirection.READWRITE) registers.add(instr2.reg2!!)
|
||||||
|
if(instr2.reg3direction==OperandDirection.WRITE || instr2.reg3direction==OperandDirection.READWRITE) registers.add(instr2.reg3!!)
|
||||||
|
if(instr2.fpReg1direction==OperandDirection.WRITE || instr2.fpReg1direction==OperandDirection.READWRITE) registers.add(instr2.fpReg1!!)
|
||||||
|
if(instr2.fpReg2direction==OperandDirection.WRITE || instr2.fpReg2direction==OperandDirection.READWRITE) registers.add(instr2.fpReg2!!)
|
||||||
|
i++
|
||||||
|
instr2 = chunk.instructions[i]
|
||||||
|
}
|
||||||
|
// it could be that the actual call is only in another code chunk, so IF we find one, we can check. Otherwise just skip the check...
|
||||||
|
if(chunk.instructions[i].fcallArgs!=null) {
|
||||||
|
val expectedRegisterLoads = chunk.instructions[i].fcallArgs!!.arguments.map { it.reg.registerNum }
|
||||||
|
require(registers.containsAll(expectedRegisterLoads)) { "not all argument registers are given a value in the preparecall-call sequence" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateChunk(globalInits, null, true)
|
||||||
blocks.forEach { block ->
|
blocks.forEach { block ->
|
||||||
if(block.isNotEmpty()) {
|
if(block.isNotEmpty()) {
|
||||||
block.children.filterIsInstance<IRInlineAsmChunk>().forEach { chunk ->
|
block.children.filterIsInstance<IRInlineAsmChunk>().forEach { chunk ->
|
||||||
@ -197,57 +257,7 @@ class IRProgram(val name: String,
|
|||||||
if(sub.chunks.isNotEmpty()) {
|
if(sub.chunks.isNotEmpty()) {
|
||||||
require(sub.chunks.first().label == sub.label) { "first chunk in subroutine should have sub name (label) as its label" }
|
require(sub.chunks.first().label == sub.label) { "first chunk in subroutine should have sub name (label) as its label" }
|
||||||
}
|
}
|
||||||
sub.chunks.forEach { chunk ->
|
sub.chunks.forEach { validateChunk(it, sub, false) }
|
||||||
if (chunk is IRCodeChunk) {
|
|
||||||
require(chunk.instructions.isNotEmpty() || chunk.label != null)
|
|
||||||
if(chunk.instructions.lastOrNull()?.opcode in OpcodesThatJump)
|
|
||||||
require(chunk.next == null) { "chunk ending with a jump or return shouldn't be linked to next" }
|
|
||||||
else {
|
|
||||||
// if chunk is NOT the last in the block, it needs to link to next.
|
|
||||||
val isLast = sub.chunks.last() === chunk
|
|
||||||
require(isLast || chunk.next != null) { "chunk needs to be linked to next" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
require(chunk.instructions.isEmpty())
|
|
||||||
if(chunk is IRInlineAsmChunk)
|
|
||||||
require(!chunk.isIR) { "inline IR-asm should have been converted into regular code chunk"}
|
|
||||||
}
|
|
||||||
chunk.instructions.withIndex().forEach { (index, instr) ->
|
|
||||||
if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) {
|
|
||||||
if(instr.opcode==Opcode.JUMPI) {
|
|
||||||
val pointervar = st.lookup(instr.labelSymbol)!!
|
|
||||||
when(pointervar) {
|
|
||||||
is IRStStaticVariable -> require(pointervar.dt==DataType.UWORD)
|
|
||||||
is IRStMemVar -> require(pointervar.dt==DataType.UWORD)
|
|
||||||
else -> throw AssemblyError("weird pointervar type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(!instr.labelSymbol.startsWith('$') && !instr.labelSymbol.first().isDigit())
|
|
||||||
require(instr.branchTarget != null) { "branching instruction to label should have branchTarget set" }
|
|
||||||
}
|
|
||||||
|
|
||||||
if(instr.opcode==Opcode.PREPARECALL) {
|
|
||||||
var i = index+1
|
|
||||||
var instr2 = chunk.instructions[i]
|
|
||||||
val registers = mutableSetOf<Int>()
|
|
||||||
while(instr2.opcode!=Opcode.SYSCALL && instr2.opcode!=Opcode.CALL && i<chunk.instructions.size-1) {
|
|
||||||
if(instr2.reg1direction==OperandDirection.WRITE || instr2.reg1direction==OperandDirection.READWRITE) registers.add(instr2.reg1!!)
|
|
||||||
if(instr2.reg2direction==OperandDirection.WRITE || instr2.reg2direction==OperandDirection.READWRITE) registers.add(instr2.reg2!!)
|
|
||||||
if(instr2.reg3direction==OperandDirection.WRITE || instr2.reg3direction==OperandDirection.READWRITE) registers.add(instr2.reg3!!)
|
|
||||||
if(instr2.fpReg1direction==OperandDirection.WRITE || instr2.fpReg1direction==OperandDirection.READWRITE) registers.add(instr2.fpReg1!!)
|
|
||||||
if(instr2.fpReg2direction==OperandDirection.WRITE || instr2.fpReg2direction==OperandDirection.READWRITE) registers.add(instr2.fpReg2!!)
|
|
||||||
i++
|
|
||||||
instr2 = chunk.instructions[i]
|
|
||||||
}
|
|
||||||
// it could be that the actual call is only in another code chunk, so IF we find one, we can check. Otherwise just skip the check...
|
|
||||||
if(chunk.instructions[i].fcallArgs!=null) {
|
|
||||||
val expectedRegisterLoads = chunk.instructions[i].fcallArgs!!.arguments.map { it.reg.registerNum }
|
|
||||||
require(registers.containsAll(expectedRegisterLoads)) { "not all argument registers are given a value in the preparecall-call sequence" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,11 @@ class VmProgramLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pass2translateSyscalls(programChunks)
|
pass2translateSyscalls(programChunks + irProgram.globalInits)
|
||||||
pass2replaceLabelsByProgIndex(programChunks, variableAddresses, subroutines)
|
pass2replaceLabelsByProgIndex(programChunks, variableAddresses, subroutines)
|
||||||
phase2relinkReplacedChunks(chunkReplacements, programChunks)
|
phase2relinkReplacedChunks(chunkReplacements, programChunks)
|
||||||
|
|
||||||
programChunks.forEach {
|
(programChunks + irProgram.globalInits).forEach {
|
||||||
it.instructions.forEach { ins ->
|
it.instructions.forEach { ins ->
|
||||||
if (ins.labelSymbol != null && ins.opcode !in OpcodesThatBranch)
|
if (ins.labelSymbol != null && ins.opcode !in OpcodesThatBranch)
|
||||||
require(ins.address != null) { "instruction with labelSymbol for a var should have value set to the memory address" }
|
require(ins.address != null) { "instruction with labelSymbol for a var should have value set to the memory address" }
|
||||||
@ -78,8 +78,8 @@ class VmProgramLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun phase2relinkReplacedChunks(
|
private fun phase2relinkReplacedChunks(
|
||||||
replacements: MutableList<Pair<IRCodeChunkBase, IRCodeChunk>>,
|
replacements: List<Pair<IRCodeChunkBase, IRCodeChunk>>,
|
||||||
programChunks: MutableList<IRCodeChunk>
|
programChunks: List<IRCodeChunk>
|
||||||
) {
|
) {
|
||||||
replacements.forEach { (old, new) ->
|
replacements.forEach { (old, new) ->
|
||||||
programChunks.forEach { chunk ->
|
programChunks.forEach { chunk ->
|
||||||
@ -97,7 +97,7 @@ class VmProgramLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pass2translateSyscalls(chunks: MutableList<IRCodeChunk>) {
|
private fun pass2translateSyscalls(chunks: List<IRCodeChunk>) {
|
||||||
chunks.forEach { chunk ->
|
chunks.forEach { chunk ->
|
||||||
chunk.instructions.withIndex().forEach { (index, ins) ->
|
chunk.instructions.withIndex().forEach { (index, ins) ->
|
||||||
if(ins.opcode == Opcode.SYSCALL) {
|
if(ins.opcode == Opcode.SYSCALL) {
|
||||||
@ -147,7 +147,7 @@ class VmProgramLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun pass2replaceLabelsByProgIndex(
|
private fun pass2replaceLabelsByProgIndex(
|
||||||
chunks: MutableList<IRCodeChunk>,
|
chunks: List<IRCodeChunk>,
|
||||||
variableAddresses: MutableMap<String, Int>,
|
variableAddresses: MutableMap<String, Int>,
|
||||||
subroutines: MutableMap<String, IRSubroutine>
|
subroutines: MutableMap<String, IRSubroutine>
|
||||||
) {
|
) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user