tweak IR call args setting now via special SETPARAM instruction

This commit is contained in:
Irmen de Jong 2023-04-13 23:45:02 +02:00
parent b55be093be
commit efd7d6f0c0
16 changed files with 178 additions and 78 deletions

View File

@ -82,9 +82,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val left = exprGen.translateExpression(call.args[0])
val right = exprGen.translateExpression(call.args[1])
addToResult(result, left, left.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=left.resultReg), null)
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1=left.resultReg, immediate = 0), null)
addToResult(result, right, right.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=right.resultReg), null)
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1=right.resultReg, immediate = 1), null)
addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null)
addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=left.resultReg), null)
return ExpressionCodeResult(result, IRDataType.BYTE, left.resultReg, -1)
@ -119,9 +119,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
@ -144,9 +144,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
@ -272,9 +272,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
@ -297,9 +297,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)

View File

@ -112,10 +112,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
DataType.STR -> {
tr = translateExpression(check.element)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 0), null)
tr = translateExpression(check.iterable)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1), null)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
@ -125,13 +125,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
DataType.ARRAY_UB, DataType.ARRAY_B -> {
tr = translateExpression(check.element)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 0), null)
tr = translateExpression(check.iterable)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 2)
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
@ -141,13 +141,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
DataType.ARRAY_UW, DataType.ARRAY_W -> {
tr = translateExpression(check.element)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 0), null)
tr = translateExpression(check.iterable)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 2)
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
@ -358,23 +358,33 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.name)) {
is StSub -> {
val result = mutableListOf<IRCodeChunkBase>()
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
val paramDt = codeGen.irType(parameter.type)
val symbol = "${fcall.name}.${parameter.name}"
if(codeGen.isZero(arg)) {
addInstr(result, IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol), null)
} else {
if (paramDt == IRDataType.FLOAT) {
val tr = translateExpression(arg)
addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, IRInstruction(Opcode.STOREM, paramDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol), null)
} else {
val tr = translateExpression(arg)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1 = tr.resultReg, labelSymbol = symbol), null)
}
}
for ((index, argspec) in fcall.args.zip(callTarget.parameters).withIndex()) {
val (arg, param) = argspec
val paramDt = codeGen.irType(param.type)
val tr = translateExpression(arg)
result += tr.chunks
if(paramDt==IRDataType.FLOAT)
addInstr(result, IRInstruction(Opcode.SETPARAM, paramDt, fpReg1 = tr.resultFpReg, immediate = index), null)
else
addInstr(result, IRInstruction(Opcode.SETPARAM, paramDt, reg1 = tr.resultReg, immediate = index), null)
}
// for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
// val paramDt = codeGen.irType(parameter.type)
// val symbol = "${fcall.name}.${parameter.name}"
// if(codeGen.isZero(arg)) {
// addInstr(result, IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol), null)
// } else {
// if (paramDt == IRDataType.FLOAT) {
// val tr = translateExpression(arg)
// addToResult(result, tr, -1, tr.resultFpReg)
// addInstr(result, IRInstruction(Opcode.STOREM, paramDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol), null)
// } else {
// val tr = translateExpression(arg)
// addToResult(result, tr, tr.resultReg, -1)
// addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1 = tr.resultReg, labelSymbol = symbol), null)
// }
// }
// }
return if(fcall.void) {
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name), null)
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)

View File

@ -197,7 +197,7 @@ sub str2uword(str string) -> uword {
; (any non-digit character will terminate the number string that is parsed)
%ir {{
loadm.w r65535,conv.str2uword.string
push.w r65535
setparam.w r65535,0
syscall 11
pop.w r0
returnr.w r0
@ -210,7 +210,7 @@ sub str2word(str string) -> word {
; (any non-digit character will terminate the number string that is parsed)
%ir {{
loadm.w r65535,conv.str2word.string
push.w r65535
setparam.w r65535,0
syscall 12
pop.w r0
returnr.w r0

View File

@ -11,7 +11,7 @@ sub print_f(float value) {
; ---- prints the floating point value (without a newline).
%ir {{
loadm.f fr65535,floats.print_f.value
push.f fr65535
setparam.f fr65535,0
syscall 25
return
}}
@ -136,7 +136,7 @@ sub rndf() -> float {
sub rndseedf(float seed) {
%ir {{
loadm.f fr65535,floats.rndseedf.seed
push.f fr65535
setparam.f fr65535,0
syscall 32
}}
}

View File

@ -179,9 +179,9 @@ math {
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
%ir {{
loadm.w r65535,math.rndseed.seed1
push.w r65535
setparam.w r65535,0
loadm.w r65535,math.rndseed.seed2
push.w r65535
setparam.w r65535,1
syscall 31
return
}}

View File

@ -85,9 +85,9 @@ string {
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
%ir {{
loadm.w r65535,string.compare.st1
push.w r65535
setparam.w r65535,0
loadm.w r65535,string.compare.st2
push.w r65535
setparam.w r65535,1
syscall 29
pop.b r0
returnr.b r0

View File

@ -16,7 +16,7 @@ sys {
; --- wait approximately the given number of jiffies (1/60th seconds)
%ir {{
loadm.w r65535,sys.wait.jiffies
push.w r65535
setparam.w r65535,0
syscall 13
}}
}
@ -64,7 +64,7 @@ sys {
; -- immediately exit the program with a return code in the A register
%ir {{
loadm.b r65535,sys.exit.returnvalue
push.b r65535
setparam.b r65535,0
syscall 1
}}
}
@ -85,7 +85,7 @@ sys {
sub gfx_enable(ubyte mode) {
%ir {{
loadm.b r65535,sys.gfx_enable.mode
push.b r65535
setparam.b r65535,0
syscall 8
}}
}
@ -93,7 +93,7 @@ sys {
sub gfx_clear(ubyte color) {
%ir {{
loadm.b r65535,sys.gfx_clear.color
push.b r65535
setparam.b r65535,0
syscall 9
}}
}
@ -101,11 +101,11 @@ sys {
sub gfx_plot(uword xx, uword yy, ubyte color) {
%ir {{
loadm.w r65535,sys.gfx_plot.xx
push.w r65535
setparam.w r65535,0
loadm.w r65535,sys.gfx_plot.yy
push.w r65535
setparam.w r65535,1
loadm.b r65535,sys.gfx_plot.color
push.b r65535
setparam.b r65535,2
syscall 10
}}
}
@ -113,9 +113,9 @@ sys {
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
%ir {{
loadm.w r65535,sys.gfx_getpixel.xx
push.w r65535
setparam.w r65535,0
loadm.w r65535,sys.gfx_getpixel.yy
push.w r65535
setparam.w r65535,1
syscall 30
pop.b r0
returnr.b r0

View File

@ -16,7 +16,7 @@ sub clear_screen() {
str @shared sequence = "\x1b[2J\x1B[H"
%ir {{
load.w r65535,txt.clear_screen.sequence
push.w r65535
setparam.w r65535,0
syscall 3
}}
}
@ -40,7 +40,7 @@ sub uppercase() {
sub chrout(ubyte char) {
%ir {{
loadm.b r65535,txt.chrout.char
push.b r65535
setparam.b r65535,0
syscall 2
}}
}
@ -48,7 +48,7 @@ sub chrout(ubyte char) {
sub print (str text) {
%ir {{
loadm.w r65535,txt.print.text
push.w r65535
setparam.w r65535,0
syscall 3
}}
}
@ -126,9 +126,9 @@ sub input_chars (uword buffer) -> ubyte {
; It assumes the keyboard is selected as I/O channel!
%ir {{
loadm.w r65535,txt.input_chars.buffer
push.w r65535
setparam.w r65535,0
load.b r65535,80
push.b r65535
setparam.b r65535,1
syscall 6
pop.b r0
returnr.b r0

View File

@ -47,9 +47,6 @@ Compiler:
- ir: peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out! and don't renumber registers above SyscallRegisterBase!)
- ir: add more optimizations in IRPeepholeOptimizer
- ir: for expressions with array indexes that occur multiple times, can we avoid loading them into new virtualregs everytime and just reuse a single virtualreg as indexer? (simple form of common subexpression elimination)
- ir: write arguments for subroutine calls in IR differently?
don't load them explicitly into the variables but use a new special instruction to do it transparently.
(vm should take care of it based on the subroutine's parameter list)
- PtAst/IR: more complex common subexpression eliminations
- vm: somehow be able to load a label address as value? (VmProgramLoader) this may require storing the program as bytecodes in actual memory though...
- 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition.

View File

@ -4,18 +4,24 @@
%import string
main {
ubyte a
sub func1() {
a++
}
sub func2() -> ubyte {
a++
return a
}
sub start() {
str name = "irmen"
reverse(name)
txt.print(name)
a=42
func1()
txt.print_ub(a)
txt.nl()
sort(name)
txt.print(name)
txt.nl()
txt.print_ub('@' in name)
txt.nl()
txt.print_ub('i' in name)
txt.print_ub(func2())
txt.nl()
floats.print_f(floats.PI)
sys.wait(60)
}
}

View File

@ -53,6 +53,7 @@ CONTROL FLOW
------------
jump location - continue running at instruction number given by location
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
setparam reg1, argpos - sets reg1 as the value for the parameter in the given position for an upcoming function call (call, callr, syscall, or even jump opcode).
call location - save current instruction location+1, continue execution at instruction nr given by location. No return value is expected.
callr reg1, location - like call but expects the routine to return a value with a returnr instruction, it then puts that in reg1
syscall value - do a systemcall identified by call number, result value(s) are pushed on value stack so need to be POPped off (depends on syscall)
@ -237,6 +238,7 @@ enum class Opcode {
JUMP,
JUMPA,
SETPARAM,
CALL,
CALLR,
SYSCALL,
@ -517,11 +519,12 @@ val instructionFormats = mutableMapOf(
Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"),
Opcode.JUMP to InstructionFormat.from("N,<a"),
Opcode.JUMPA to InstructionFormat.from("N,<a"),
Opcode.SETPARAM to InstructionFormat.from("BW,<r1,<i | F,<fr1,<i"),
Opcode.CALL to InstructionFormat.from("N,<a"),
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
Opcode.RETURN to InstructionFormat.from("N"),
Opcode.RETURNR to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.RETURNR to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.BSTCC to InstructionFormat.from("N,<a"),
Opcode.BSTCS to InstructionFormat.from("N,<a"),
Opcode.BSTEQ to InstructionFormat.from("N,<a"),
@ -698,7 +701,12 @@ data class IRInstruction(
if(format.fpReg1==OperandDirection.UNUSED) require(fpReg1==null) { "invalid fpReg1" }
if(format.fpReg2==OperandDirection.UNUSED) require(fpReg2==null) { "invalid fpReg2" }
if(format.immediate) {
if(type==IRDataType.FLOAT) require(immediateFp !=null) {"missing immediate fp value"}
if(type==IRDataType.FLOAT) {
if(opcode!=Opcode.SETPARAM)
require(immediateFp !=null) {"missing immediate fp value"}
else
require(immediateFp==null) {"setparam never has immediateFp only immediate"}
}
else require(immediate!=null || labelSymbol!=null) {"missing immediate value or labelsymbol"}
}
if(type!=IRDataType.FLOAT)

View File

@ -198,6 +198,10 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, placeholder
null -> {}
}
}
if(format.immediate && opcode==Opcode.SETPARAM && immediateInt==null) {
immediateInt = immediateFp!!.toInt()
immediateFp = null
}
if(format.address!=OperandDirection.UNUSED && address==null && labelSymbol==null)
throw IRParseException("requires address or symbol for $line")

View File

@ -92,6 +92,7 @@ uword sys.wait.jiffies
</PARAMS>
<INLINEASM LABEL="sys.wait" IR="true" POS="[library:/prog8lib/virtual/syslib.p8: line 17 col 10-13]">
loadm.w r0,sys.wait.jiffies
setparam.w r0,0
syscall 13
</INLINEASM>
<CODE>

View File

@ -80,7 +80,12 @@ enum class Syscall {
RNDF,
STRING_CONTAINS,
BYTEARRAY_CONTAINS,
WORDARRAY_CONTAINS
WORDARRAY_CONTAINS;
companion object {
private val VALUES = values()
fun fromInt(value: Int) = VALUES[value]
}
}
object SysCalls {

View File

@ -176,6 +176,7 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.STOREZI -> InsSTOREZI(ins)
Opcode.JUMP -> InsJUMP(ins)
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
Opcode.SETPARAM -> InsSETPARAM(ins)
Opcode.CALL, Opcode.CALLR -> InsCALL(ins)
Opcode.SYSCALL -> InsSYSCALL(ins)
Opcode.RETURN -> InsRETURN()
@ -351,8 +352,19 @@ class VirtualMachine(irProgram: IRProgram) {
}
private fun InsSYSCALL(i: IRInstruction) {
val call = Syscall.values()[i.immediate!!]
SysCalls.call(call, this) // note: any result value(s) are pushed on the value stack
// put the syscall's arguments that were prepared onto the stack
for(value in syscallParams) {
if(value.dt==null)
break
when(value.dt!!) {
IRDataType.BYTE -> valueStack.push(value.value as UByte)
IRDataType.WORD -> valueStack.pushw(value.value as UShort)
IRDataType.FLOAT -> valueStack.pushf(value.value as Float)
}
value.dt=null
}
val call = Syscall.fromInt(i.immediate!!)
SysCalls.call(call, this) // note: any result value(s) are pushed back on the value stack
nextPc()
}
@ -589,6 +601,31 @@ class VirtualMachine(irProgram: IRProgram) {
branchTo(i)
}
private class SyscallParamValue(var dt: IRDataType?, var value: Comparable<*>?)
private val syscallParams = Array(100) { SyscallParamValue(null, null) }
private fun InsSETPARAM(i: IRInstruction) {
// store the argument value into the retrieved subroutine's parameter variable (already cached in the instruction's address)
// the reason this is a special instruction is to be flexible in implementing the call convention
val address = i.address
if(address==null) {
// this param is for a SYSCALL (that has no param variable address, instead it goes via the stack)
syscallParams[i.immediate!!].dt = i.type!!
syscallParams[i.immediate!!].value = when(i.type!!) {
IRDataType.BYTE -> registers.getUB(i.reg1!!)
IRDataType.WORD -> registers.getUW(i.reg1!!)
IRDataType.FLOAT -> registers.getFloat(i.fpReg1!!)
}
} else {
when (i.type!!) {
IRDataType.BYTE -> memory.setUB(address, registers.getUB(i.reg1!!))
IRDataType.WORD -> memory.setUW(address, registers.getUW(i.reg1!!))
IRDataType.FLOAT -> memory.setFloat(address, registers.getFloat(i.fpReg1!!))
}
}
nextPc()
}
private fun InsCALL(i: IRInstruction) {
callStack.push(CallSiteContext(pcChunk, pcIndex+1, i.reg1, i.fpReg1))
branchTo(i)

View File

@ -7,10 +7,12 @@ import prog8.intermediate.*
class VmProgramLoader {
private val placeholders = mutableMapOf<Pair<IRCodeChunk, Int>, String>() // program chunk+index to symbolname
private val subroutines = mutableMapOf<String, IRSubroutine>() // label to subroutine node
fun load(irProgram: IRProgram, memory: Memory): List<IRCodeChunk> {
placeholders.clear()
irProgram.validate()
placeholders.clear()
subroutines.clear()
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
val variableAddresses = allocations.allocations.toMutableMap()
val programChunks = mutableListOf<IRCodeChunk>()
@ -48,6 +50,7 @@ class VmProgramLoader {
}
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO
is IRSubroutine -> {
subroutines[child.label] = child
child.chunks.forEach { chunk ->
when (chunk) {
is IRInlineAsmChunk -> {
@ -58,13 +61,14 @@ class VmProgramLoader {
is IRCodeChunk -> programChunks += chunk
else -> throw AssemblyError("weird chunk type")
}
} }
}
}
}
}
}
pass2translateSyscalls(programChunks)
pass2replaceLabelsByProgIndex(programChunks, variableAddresses)
pass2replaceLabelsByProgIndex(programChunks, variableAddresses, subroutines)
phase2relinkReplacedChunks(chunkReplacements, programChunks)
programChunks.forEach {
@ -137,7 +141,8 @@ class VmProgramLoader {
private fun pass2replaceLabelsByProgIndex(
chunks: MutableList<IRCodeChunk>,
variableAddresses: MutableMap<String, Int>
variableAddresses: MutableMap<String, Int>,
subroutines: MutableMap<String, IRSubroutine>
) {
for((ref, label) in placeholders) {
val (chunk, line) = ref
@ -168,6 +173,33 @@ class VmProgramLoader {
chunk.instructions[line] = chunk.instructions[line].copy(address = replacement)
}
}
chunks.forEach {
it.instructions.withIndex().forEach { (index, ins) ->
if(ins.opcode==Opcode.SETPARAM && ins.address==null) {
val call = findCall(it, index)
if(call.opcode==Opcode.SYSCALL) {
// there is no variable to set, SYSCALLs get their args from the stack.
} else if(call.labelSymbol!=null) {
// set the address in the instruction to the subroutine's parameter variable's address
// this avoids having to look it up every time the SETPARAM instruction is encountered during execution
val target = subroutines.getValue(call.labelSymbol!!)
val paramVar = target.parameters[ins.immediate!!]
val address = variableAddresses.getValue(paramVar.name)
it.instructions[index] = ins.copy(address = address)
} else
throw IRParseException("weird call $call")
}
}
}
}
private val functionCallOpcodes = setOf(Opcode.CALL, Opcode.CALLR, Opcode.SYSCALL, Opcode.JUMP, Opcode.JUMPA)
private fun findCall(it: IRCodeChunk, startIndex: Int): IRInstruction {
var idx = startIndex
while(it.instructions[idx].opcode !in functionCallOpcodes)
idx++
return it.instructions[idx]
}
private fun varsToMemory(