mirror of
https://github.com/irmen/prog8.git
synced 2024-08-02 07:29:05 +00:00
new IR call and return instructions to deal with returnregisters
This commit is contained in:
parent
39132327cc
commit
78a097585d
@ -954,17 +954,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol=fcall.name), null)
|
if(fcall.void)
|
||||||
if(fcall.type==DataType.FLOAT) {
|
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol=fcall.name), null)
|
||||||
if (!fcall.void && resultFpRegister != 0) {
|
else {
|
||||||
// Call convention: result value is in fr0, so put it in the required register instead.
|
if(fcall.type==DataType.FLOAT)
|
||||||
addInstr(result, IRInstruction(Opcode.LOADR, IRDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0), null)
|
addInstr(result, IRInstruction(Opcode.CALLRVAL, IRDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol=fcall.name), null)
|
||||||
}
|
else
|
||||||
} else {
|
addInstr(result, IRInstruction(Opcode.CALLRVAL, codeGen.irType(fcall.type), reg1=resultRegister, labelSymbol=fcall.name), null)
|
||||||
if (!fcall.void && resultRegister != 0) {
|
|
||||||
// Call convention: result value is in r0, so put it in the required register instead.
|
|
||||||
addInstr(result, IRInstruction(Opcode.LOADR, codeGen.irType(fcall.type), reg1 = resultRegister, reg2 = 0), null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -983,6 +979,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
addInstr(result, IRInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr), null)
|
addInstr(result, IRInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr), null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// just a regular call without using Vm register call convention: the value is returned in CPU registers!
|
||||||
addInstr(result, IRInstruction(Opcode.CALL, value=callTarget.address.toInt()), null)
|
addInstr(result, IRInstruction(Opcode.CALL, value=callTarget.address.toInt()), null)
|
||||||
if(!fcall.void) {
|
if(!fcall.void) {
|
||||||
when(callTarget.returns.size) {
|
when(callTarget.returns.size) {
|
||||||
|
@ -68,6 +68,7 @@ class IRCodeGen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(options.optimize) {
|
if(options.optimize) {
|
||||||
|
// TODO integrate into peephole optimizer above
|
||||||
val opt = IROptimizer(irProg)
|
val opt = IROptimizer(irProg)
|
||||||
opt.optimize()
|
opt.optimize()
|
||||||
}
|
}
|
||||||
@ -1265,14 +1266,20 @@ class IRCodeGen(
|
|||||||
private fun translate(ret: PtReturn): IRCodeChunks {
|
private fun translate(ret: PtReturn): IRCodeChunks {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
val value = ret.value
|
val value = ret.value
|
||||||
if(value!=null) {
|
if(value==null) {
|
||||||
// Call Convention: return value is always returned in r0 (or fr0 if float)
|
addInstr(result, IRInstruction(Opcode.RETURN), null)
|
||||||
result += if(value.type==DataType.FLOAT)
|
} else {
|
||||||
expressionEval.translateExpression(value, -1, 0)
|
if(value.type==DataType.FLOAT) {
|
||||||
else
|
val reg = registers.nextFreeFloat()
|
||||||
expressionEval.translateExpression(value, 0, -1)
|
result += expressionEval.translateExpression(value, -1, reg)
|
||||||
|
addInstr(result, IRInstruction(Opcode.RETURNREG, IRDataType.FLOAT, fpReg1 = reg), null)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val reg = registers.nextFree()
|
||||||
|
result += expressionEval.translateExpression(value, reg, -1)
|
||||||
|
addInstr(result, IRInstruction(Opcode.RETURNREG, irType(value.type) , reg1=reg), null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
addInstr(result, IRInstruction(Opcode.RETURN), null)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove useless RETURN
|
// remove useless RETURN
|
||||||
if(ins.opcode == Opcode.RETURN && idx>0) {
|
if(idx>0 && (ins.opcode == Opcode.RETURN || ins.opcode==Opcode.RETURNREG)) {
|
||||||
val previous = chunk.instructions[idx-1] as? IRInstruction
|
val previous = chunk.instructions[idx-1] as? IRInstruction
|
||||||
if(previous?.opcode in OpcodesThatJump) {
|
if(previous?.opcode in OpcodesThatJump) {
|
||||||
chunk.instructions.removeAt(idx)
|
chunk.instructions.removeAt(idx)
|
||||||
|
@ -5,6 +5,7 @@ import prog8.intermediate.SyscallRegisterBase
|
|||||||
|
|
||||||
internal class RegisterPool {
|
internal class RegisterPool {
|
||||||
// reserve 0,1,2 for return values of subroutine calls and syscalls
|
// reserve 0,1,2 for return values of subroutine calls and syscalls
|
||||||
|
// TODO set this back to 0 once 'resultRegister' has been removed everywhere?
|
||||||
private var firstFree: Int=3
|
private var firstFree: Int=3
|
||||||
private var firstFreeFloat: Int=3
|
private var firstFreeFloat: Int=3
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package prog8.iroptimizer
|
|||||||
|
|
||||||
import prog8.intermediate.*
|
import prog8.intermediate.*
|
||||||
|
|
||||||
|
// TODO integrate into peephole optimizer
|
||||||
|
|
||||||
internal class IROptimizer(val program: IRProgram) {
|
internal class IROptimizer(val program: IRProgram) {
|
||||||
fun optimize() {
|
fun optimize() {
|
||||||
program.blocks.forEach { block ->
|
program.blocks.forEach { block ->
|
||||||
@ -36,7 +38,7 @@ internal class IROptimizer(val program: IRProgram) {
|
|||||||
val i1 = first.value
|
val i1 = first.value
|
||||||
val i2 = second.value
|
val i2 = second.value
|
||||||
// replace call + return --> jump
|
// replace call + return --> jump
|
||||||
if(i1.opcode==Opcode.CALL && i2.opcode==Opcode.RETURN) {
|
if((i1.opcode==Opcode.CALL || i1.opcode==Opcode.CALLRVAL) && i2.opcode==Opcode.RETURN) {
|
||||||
elt.instructions[first.index] = IRInstruction(Opcode.JUMP, value=i1.value, labelSymbol = i1.labelSymbol, branchTarget = i1.branchTarget)
|
elt.instructions[first.index] = IRInstruction(Opcode.JUMP, value=i1.value, labelSymbol = i1.labelSymbol, branchTarget = i1.branchTarget)
|
||||||
elt.instructions[second.index] = IRInstruction(Opcode.NOP)
|
elt.instructions[second.index] = IRInstruction(Opcode.NOP)
|
||||||
if(second.index==elt.instructions.size-1) {
|
if(second.index==elt.instructions.size-1) {
|
||||||
|
@ -198,7 +198,7 @@ sub str2uword(str string) -> uword {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65500,conv.str2uword.string
|
loadm.w r65500,conv.str2uword.string
|
||||||
syscall 11
|
syscall 11
|
||||||
return
|
returnreg.w r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ sub str2word(str string) -> word {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65500,conv.str2word.string
|
loadm.w r65500,conv.str2word.string
|
||||||
syscall 12
|
syscall 12
|
||||||
return
|
returnreg.w r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ sub pow(float value, float power) -> float {
|
|||||||
loadm.f fr0,floats.pow.value
|
loadm.f fr0,floats.pow.value
|
||||||
loadm.f fr1,floats.pow.power
|
loadm.f fr1,floats.pow.power
|
||||||
fpow.f fr0,fr1
|
fpow.f fr0,fr1
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ sub fabs(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.fabs.value
|
loadm.f fr0,floats.fabs.value
|
||||||
fabs.f fr0,fr0
|
fabs.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ sub sin(float angle) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.sin.angle
|
loadm.f fr0,floats.sin.angle
|
||||||
fsin.f fr0,fr0
|
fsin.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ sub cos(float angle) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.cos.angle
|
loadm.f fr0,floats.cos.angle
|
||||||
fcos.f fr0,fr0
|
fcos.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ sub tan(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.tan.value
|
loadm.f fr0,floats.tan.value
|
||||||
ftan.f fr0,fr0
|
ftan.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ sub atan(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.atan.value
|
loadm.f fr0,floats.atan.value
|
||||||
fatan.f fr0,fr0
|
fatan.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ sub ln(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.ln.value
|
loadm.f fr0,floats.ln.value
|
||||||
fln.f fr0,fr0
|
fln.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ sub log2(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.log2.value
|
loadm.f fr0,floats.log2.value
|
||||||
flog.f fr0,fr0
|
flog.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ sub sqrt(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.sqrt.value
|
loadm.f fr0,floats.sqrt.value
|
||||||
sqrt.f fr0,fr0
|
sqrt.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ sub round(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.round.value
|
loadm.f fr0,floats.round.value
|
||||||
fround.f fr0,fr0
|
fround.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ sub floor(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.floor.value
|
loadm.f fr0,floats.floor.value
|
||||||
ffloor.f fr0,fr0
|
ffloor.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,14 +120,14 @@ sub ceil(float value) -> float {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr0,floats.ceil.value
|
loadm.f fr0,floats.ceil.value
|
||||||
fceil.f fr0,fr0
|
fceil.f fr0,fr0
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub rndf() -> float {
|
sub rndf() -> float {
|
||||||
%ir {{
|
%ir {{
|
||||||
syscall 35
|
syscall 35
|
||||||
return
|
returnreg.f fr0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,14 +162,14 @@ math {
|
|||||||
sub rnd() -> ubyte {
|
sub rnd() -> ubyte {
|
||||||
%ir {{
|
%ir {{
|
||||||
syscall 33
|
syscall 33
|
||||||
return
|
returnreg.b r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub rndw() -> uword {
|
sub rndw() -> uword {
|
||||||
%ir {{
|
%ir {{
|
||||||
syscall 34
|
syscall 34
|
||||||
return
|
returnreg.w r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ string {
|
|||||||
loadm.w r65500,string.compare.st1
|
loadm.w r65500,string.compare.st1
|
||||||
loadm.w r65501,string.compare.st2
|
loadm.w r65501,string.compare.st2
|
||||||
syscall 29
|
syscall 29
|
||||||
return
|
returnreg.b r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ sys {
|
|||||||
loadm.w r65500,sys.gfx_getpixel.xx
|
loadm.w r65500,sys.gfx_getpixel.xx
|
||||||
loadm.w r65501,sys.gfx_getpixel.yy
|
loadm.w r65501,sys.gfx_getpixel.yy
|
||||||
syscall 30
|
syscall 30
|
||||||
return
|
returnreg.b r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ sub input_chars (uword buffer) -> ubyte {
|
|||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65500,txt.input_chars.buffer
|
loadm.w r65500,txt.input_chars.buffer
|
||||||
syscall 6
|
syscall 6
|
||||||
return
|
returnreg.b r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,7 @@ TODO
|
|||||||
|
|
||||||
For next minor release
|
For next minor release
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
- IR: don't hardcode r0/fr0 as return registers.
|
- get rid of ResultRegister in IR codegen? as the calls now encode this into the new opcodes...
|
||||||
instead have RETURN -> returns void, RETURNREG <register> -> return value from given register
|
|
||||||
also CALL -> void call, CALLRVAL -> specify register to put call result in. CALLRVAL r0, functionThatReturnsInt
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -47,17 +47,13 @@ storezx reg1, address - store zero at memory address, indexed by
|
|||||||
|
|
||||||
CONTROL FLOW
|
CONTROL FLOW
|
||||||
------------
|
------------
|
||||||
Possible subroutine call convention:
|
|
||||||
Set parameters in Reg 0, 1, 2... before call. Return value set in Reg 0 before return.
|
|
||||||
But you can decide whatever you want because here we just care about jumping and returning the flow of control.
|
|
||||||
Saving/restoring registers is possible with PUSH and POP instructions.
|
|
||||||
|
|
||||||
jump location - continue running at instruction number given by location
|
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)
|
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
|
||||||
call location - save current instruction location+1, continue execution at instruction nr given by location
|
call location - save current instruction location+1, continue execution at instruction nr given by location. Expect no return value.
|
||||||
calli reg1 - save current instruction location+1, continue execution at instruction number in reg1
|
callrval reg1, location - like call but expects a return value from a returnreg instruction, and puts that in reg1
|
||||||
syscall value - do a systemcall identified by call number
|
syscall value - do a systemcall identified by call number
|
||||||
return - restore last saved instruction location and continue at that instruction
|
return - restore last saved instruction location and continue at that instruction. No return value.
|
||||||
|
returnreg reg1 - like return, but also returns a value to the caller via reg1
|
||||||
|
|
||||||
|
|
||||||
BRANCHING and CONDITIONALS
|
BRANCHING and CONDITIONALS
|
||||||
@ -232,8 +228,10 @@ enum class Opcode {
|
|||||||
JUMP,
|
JUMP,
|
||||||
JUMPA,
|
JUMPA,
|
||||||
CALL,
|
CALL,
|
||||||
|
CALLRVAL,
|
||||||
SYSCALL,
|
SYSCALL,
|
||||||
RETURN,
|
RETURN,
|
||||||
|
RETURNREG,
|
||||||
|
|
||||||
BSTCC,
|
BSTCC,
|
||||||
BSTCS,
|
BSTCS,
|
||||||
@ -363,14 +361,17 @@ enum class Opcode {
|
|||||||
val OpcodesThatJump = setOf(
|
val OpcodesThatJump = setOf(
|
||||||
Opcode.JUMP,
|
Opcode.JUMP,
|
||||||
Opcode.JUMPA,
|
Opcode.JUMPA,
|
||||||
Opcode.RETURN
|
Opcode.RETURN,
|
||||||
|
Opcode.RETURNREG
|
||||||
)
|
)
|
||||||
|
|
||||||
val OpcodesThatBranch = setOf(
|
val OpcodesThatBranch = setOf(
|
||||||
Opcode.JUMP,
|
Opcode.JUMP,
|
||||||
Opcode.JUMPA,
|
Opcode.JUMPA,
|
||||||
Opcode.RETURN,
|
Opcode.RETURN,
|
||||||
|
Opcode.RETURNREG,
|
||||||
Opcode.CALL,
|
Opcode.CALL,
|
||||||
|
Opcode.CALLRVAL,
|
||||||
Opcode.SYSCALL,
|
Opcode.SYSCALL,
|
||||||
Opcode.BSTCC,
|
Opcode.BSTCC,
|
||||||
Opcode.BSTCS,
|
Opcode.BSTCS,
|
||||||
@ -412,6 +413,7 @@ val OpcodesWithMemoryAddressAsValue = setOf(
|
|||||||
Opcode.JUMP,
|
Opcode.JUMP,
|
||||||
Opcode.JUMPA,
|
Opcode.JUMPA,
|
||||||
Opcode.CALL,
|
Opcode.CALL,
|
||||||
|
Opcode.CALLRVAL,
|
||||||
Opcode.BSTCC,
|
Opcode.BSTCC,
|
||||||
Opcode.BSTCS,
|
Opcode.BSTCS,
|
||||||
Opcode.BSTEQ,
|
Opcode.BSTEQ,
|
||||||
@ -551,8 +553,10 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.JUMP to InstructionFormat.from("N,<v"),
|
Opcode.JUMP to InstructionFormat.from("N,<v"),
|
||||||
Opcode.JUMPA to InstructionFormat.from("N,<v"),
|
Opcode.JUMPA to InstructionFormat.from("N,<v"),
|
||||||
Opcode.CALL to InstructionFormat.from("N,<v"),
|
Opcode.CALL to InstructionFormat.from("N,<v"),
|
||||||
|
Opcode.CALLRVAL to InstructionFormat.from("BW,<r1,<v | F,<fr1,<v"),
|
||||||
Opcode.SYSCALL to InstructionFormat.from("N,<v"),
|
Opcode.SYSCALL to InstructionFormat.from("N,<v"),
|
||||||
Opcode.RETURN to InstructionFormat.from("N"),
|
Opcode.RETURN to InstructionFormat.from("N"),
|
||||||
|
Opcode.RETURNREG to InstructionFormat.from("BW,<r1 | F,<fr1"),
|
||||||
Opcode.BSTCC to InstructionFormat.from("N,<v"),
|
Opcode.BSTCC to InstructionFormat.from("N,<v"),
|
||||||
Opcode.BSTCS to InstructionFormat.from("N,<v"),
|
Opcode.BSTCS to InstructionFormat.from("N,<v"),
|
||||||
Opcode.BSTEQ to InstructionFormat.from("N,<v"),
|
Opcode.BSTEQ to InstructionFormat.from("N,<v"),
|
||||||
|
@ -134,7 +134,7 @@ class IRProgram(val name: String,
|
|||||||
|
|
||||||
// link all jump and branching instructions to their target
|
// link all jump and branching instructions to their target
|
||||||
chunk.instructions.forEach {
|
chunk.instructions.forEach {
|
||||||
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.labelSymbol!=null)
|
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNREG && it.labelSymbol!=null)
|
||||||
it.branchTarget = labeledChunks.getValue(it.labelSymbol)
|
it.branchTarget = labeledChunks.getValue(it.labelSymbol)
|
||||||
// note: branches with an address value cannot be linked to something...
|
// note: branches with an address value cannot be linked to something...
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,11 @@ class BreakpointException(val pcChunk: IRCodeChunk, val pcIndex: Int): Exception
|
|||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
class VirtualMachine(irProgram: IRProgram) {
|
class VirtualMachine(irProgram: IRProgram) {
|
||||||
|
class CallSiteContext(val returnChunk: IRCodeChunk, val returnIndex: Int, val returnValueReg: Int?, val returnValueFpReg: Int?)
|
||||||
val memory = Memory()
|
val memory = Memory()
|
||||||
val program: List<IRCodeChunk>
|
val program: List<IRCodeChunk>
|
||||||
val registers = Registers()
|
val registers = Registers()
|
||||||
val callStack = Stack<Pair<IRCodeChunk, Int>>()
|
val callStack = Stack<CallSiteContext>()
|
||||||
val valueStack = Stack<UByte>() // max 128 entries
|
val valueStack = Stack<UByte>() // max 128 entries
|
||||||
var breakpointHandler: ((pcChunk: IRCodeChunk, pcIndex: Int) -> Unit)? = null // can set custom breakpoint handler
|
var breakpointHandler: ((pcChunk: IRCodeChunk, pcIndex: Int) -> Unit)? = null // can set custom breakpoint handler
|
||||||
var pcChunk = IRCodeChunk(null, null)
|
var pcChunk = IRCodeChunk(null, null)
|
||||||
@ -170,8 +171,10 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
Opcode.JUMP -> InsJUMP(ins)
|
Opcode.JUMP -> InsJUMP(ins)
|
||||||
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
|
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
|
||||||
Opcode.CALL -> InsCALL(ins)
|
Opcode.CALL -> InsCALL(ins)
|
||||||
|
Opcode.CALLRVAL -> InsCALLRVAL(ins)
|
||||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||||
Opcode.RETURN -> InsRETURN()
|
Opcode.RETURN -> InsRETURN()
|
||||||
|
Opcode.RETURNREG -> InsRETURNREG(ins)
|
||||||
Opcode.BSTCC -> InsBSTCC(ins)
|
Opcode.BSTCC -> InsBSTCC(ins)
|
||||||
Opcode.BSTCS -> InsBSTCS(ins)
|
Opcode.BSTCS -> InsBSTCS(ins)
|
||||||
Opcode.BSTEQ -> InsBSTEQ(ins)
|
Opcode.BSTEQ -> InsBSTEQ(ins)
|
||||||
@ -578,7 +581,12 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun InsCALL(i: IRInstruction) {
|
private fun InsCALL(i: IRInstruction) {
|
||||||
callStack.push(Pair(pcChunk, pcIndex+1))
|
callStack.push(CallSiteContext(pcChunk, pcIndex+1, null, null))
|
||||||
|
branchTo(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun InsCALLRVAL(i: IRInstruction) {
|
||||||
|
callStack.push(CallSiteContext(pcChunk, pcIndex+1, i.reg1, i.fpReg1))
|
||||||
branchTo(i)
|
branchTo(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,9 +594,49 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
if(callStack.isEmpty())
|
if(callStack.isEmpty())
|
||||||
exit(0)
|
exit(0)
|
||||||
else {
|
else {
|
||||||
val (chunk, idx) = callStack.pop()
|
val context = callStack.pop()
|
||||||
pcChunk = chunk
|
pcChunk = context.returnChunk
|
||||||
pcIndex = idx
|
pcIndex = context.returnIndex
|
||||||
|
// ignore any return values.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun InsRETURNREG(i: IRInstruction) {
|
||||||
|
if(callStack.isEmpty())
|
||||||
|
exit(0)
|
||||||
|
else {
|
||||||
|
val context = callStack.pop()
|
||||||
|
when (i.type!!) {
|
||||||
|
IRDataType.BYTE -> {
|
||||||
|
if(context.returnValueReg!=null)
|
||||||
|
registers.setUB(context.returnValueReg, registers.getUB(i.reg1!!))
|
||||||
|
else {
|
||||||
|
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
|
||||||
|
if(callInstr.opcode!=Opcode.CALL)
|
||||||
|
throw IllegalArgumentException("missing return value reg")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRDataType.WORD -> {
|
||||||
|
if(context.returnValueReg!=null)
|
||||||
|
registers.setUW(context.returnValueReg, registers.getUW(i.reg1!!))
|
||||||
|
else {
|
||||||
|
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
|
||||||
|
if(callInstr.opcode!=Opcode.CALL)
|
||||||
|
throw IllegalArgumentException("missing return value reg")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IRDataType.FLOAT -> {
|
||||||
|
if(context.returnValueFpReg!=null)
|
||||||
|
registers.setFloat(context.returnValueFpReg, registers.getFloat(i.fpReg1!!))
|
||||||
|
else {
|
||||||
|
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
|
||||||
|
if(callInstr.opcode!=Opcode.CALL)
|
||||||
|
throw IllegalArgumentException("missing return value reg")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pcChunk = context.returnChunk
|
||||||
|
pcIndex = context.returnIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user