mirror of
https://github.com/irmen/prog8.git
synced 2025-02-08 16:30:28 +00:00
ir: added preparecall 'meta' instruction for functioncalls
This commit is contained in:
parent
958b5c0780
commit
c319233ddc
@ -71,6 +71,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
|
|
||||||
private fun funcCallfar(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
private fun funcCallfar(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||||
val bankTr = exprGen.translateExpression(call.args[0])
|
val bankTr = exprGen.translateExpression(call.args[0])
|
||||||
val addressTr = exprGen.translateExpression(call.args[1])
|
val addressTr = exprGen.translateExpression(call.args[1])
|
||||||
val argumentwordTr = exprGen.translateExpression(call.args[2])
|
val argumentwordTr = exprGen.translateExpression(call.args[2])
|
||||||
@ -112,6 +113,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
|
|
||||||
private fun funcStringCompare(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
private fun funcStringCompare(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||||
val left = exprGen.translateExpression(call.args[0])
|
val left = exprGen.translateExpression(call.args[0])
|
||||||
val right = exprGen.translateExpression(call.args[1])
|
val right = exprGen.translateExpression(call.args[1])
|
||||||
addToResult(result, left, left.resultReg, -1)
|
addToResult(result, left, left.resultReg, -1)
|
||||||
@ -146,6 +148,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
else -> throw IllegalArgumentException("weird type")
|
else -> throw IllegalArgumentException("weird type")
|
||||||
}
|
}
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||||
val tr = exprGen.translateExpression(call.args[0])
|
val tr = exprGen.translateExpression(call.args[0])
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
val lengthReg = codeGen.registers.nextFree()
|
val lengthReg = codeGen.registers.nextFree()
|
||||||
@ -167,6 +170,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
else -> throw IllegalArgumentException("weird type")
|
else -> throw IllegalArgumentException("weird type")
|
||||||
}
|
}
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||||
val tr = exprGen.translateExpression(call.args[0])
|
val tr = exprGen.translateExpression(call.args[0])
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
val lengthReg = codeGen.registers.nextFree()
|
val lengthReg = codeGen.registers.nextFree()
|
||||||
@ -310,6 +314,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
else -> throw IllegalArgumentException("weird type to reverse")
|
else -> throw IllegalArgumentException("weird type to reverse")
|
||||||
}
|
}
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||||
val tr = exprGen.translateExpression(call.args[0])
|
val tr = exprGen.translateExpression(call.args[0])
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
val lengthReg = codeGen.registers.nextFree()
|
val lengthReg = codeGen.registers.nextFree()
|
||||||
@ -333,6 +338,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
else -> throw IllegalArgumentException("weird type to sort")
|
else -> throw IllegalArgumentException("weird type to sort")
|
||||||
}
|
}
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||||
val tr = exprGen.translateExpression(call.args[0])
|
val tr = exprGen.translateExpression(call.args[0])
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
val lengthReg = codeGen.registers.nextFree()
|
val lengthReg = codeGen.registers.nextFree()
|
||||||
@ -356,6 +362,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
|
|
||||||
private fun funcClamp(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
private fun funcClamp(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||||
val type = irType(call.type)
|
val type = irType(call.type)
|
||||||
val valueTr = exprGen.translateExpression(call.args[0])
|
val valueTr = exprGen.translateExpression(call.args[0])
|
||||||
val minimumTr = exprGen.translateExpression(call.args[1])
|
val minimumTr = exprGen.translateExpression(call.args[1])
|
||||||
|
@ -122,6 +122,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
when(check.iterable.type) {
|
when(check.iterable.type) {
|
||||||
DataType.STR -> {
|
DataType.STR -> {
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||||
val elementTr = translateExpression(check.element)
|
val elementTr = translateExpression(check.element)
|
||||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||||
val iterableTr = translateExpression(check.iterable)
|
val iterableTr = translateExpression(check.iterable)
|
||||||
@ -130,6 +131,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||||
}
|
}
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||||
val elementTr = translateExpression(check.element)
|
val elementTr = translateExpression(check.element)
|
||||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||||
val iterableTr = translateExpression(check.iterable)
|
val iterableTr = translateExpression(check.iterable)
|
||||||
@ -141,6 +143,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||||
}
|
}
|
||||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||||
val elementTr = translateExpression(check.element)
|
val elementTr = translateExpression(check.element)
|
||||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||||
val iterableTr = translateExpression(check.iterable)
|
val iterableTr = translateExpression(check.iterable)
|
||||||
@ -381,6 +384,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.name)) {
|
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.name)) {
|
||||||
is StSub -> {
|
is StSub -> {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = callTarget.parameters.size), null)
|
||||||
// assign the arguments
|
// assign the arguments
|
||||||
val argRegisters = mutableListOf<FunctionCallArgs.ArgumentSpec>()
|
val argRegisters = mutableListOf<FunctionCallArgs.ArgumentSpec>()
|
||||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||||
@ -401,8 +405,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFree(), null)
|
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFree(), null)
|
||||||
}
|
}
|
||||||
// create the call
|
// create the call
|
||||||
val call = IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec))
|
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec)), null)
|
||||||
addInstr(result, call, null)
|
|
||||||
return if(fcall.void)
|
return if(fcall.void)
|
||||||
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||||
else if(fcall.type==DataType.FLOAT)
|
else if(fcall.type==DataType.FLOAT)
|
||||||
@ -412,6 +415,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
}
|
}
|
||||||
is StRomSub -> {
|
is StRomSub -> {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = callTarget.parameters.size), null)
|
||||||
// assign the arguments
|
// assign the arguments
|
||||||
val argRegisters = mutableListOf<FunctionCallArgs.ArgumentSpec>()
|
val argRegisters = mutableListOf<FunctionCallArgs.ArgumentSpec>()
|
||||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||||
|
@ -466,7 +466,11 @@ class TestVmCodeGen: FunSpec({
|
|||||||
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
val result = codegen.generate(program, st, options, errors) as VmAssemblyProgram
|
||||||
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
val irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||||
irChunks.size shouldBe 1
|
irChunks.size shouldBe 1
|
||||||
val callInstr = irChunks.single().instructions.single()
|
irChunks[0].instructions.size shouldBe 2
|
||||||
|
val preparecallInstr = irChunks[0].instructions[0]
|
||||||
|
preparecallInstr.opcode shouldBe Opcode.PREPARECALL
|
||||||
|
preparecallInstr.immediate shouldBe 0
|
||||||
|
val callInstr = irChunks[0].instructions[1]
|
||||||
callInstr.opcode shouldBe Opcode.CALL
|
callInstr.opcode shouldBe Opcode.CALL
|
||||||
callInstr.address shouldBe 0x5000
|
callInstr.address shouldBe 0x5000
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,20 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import floats
|
|
||||||
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte[] barray = [11,22,33]
|
ubyte arg3 = 200
|
||||||
uword[] warray = [$1234,$5678,$abcd]
|
uword result = calc(101, 202, arg3)
|
||||||
uword[] @split split_warray = [$1234,$5678,$abcd]
|
txt.print_uw(result)
|
||||||
float[] float_array = [11.11,22.22,33.33]
|
|
||||||
|
|
||||||
txt.print("incr of 1: ")
|
str name = "irmen"
|
||||||
txt.print_uw(&barray)
|
ubyte[] array = [1,2,3,4]
|
||||||
txt.spc()
|
bool xx = 44 in array
|
||||||
txt.print_uw(&barray[0])
|
bool yy = 'a' in name
|
||||||
txt.spc()
|
}
|
||||||
txt.print_uw(&barray[1])
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&barray[2])
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
txt.print("incr of 2: ")
|
sub calc(ubyte a1, ubyte a2, ubyte a3) -> uword {
|
||||||
txt.print_uw(&warray)
|
return a1 as uword + a2 + a3
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&warray[0])
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&warray[1])
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&warray[2])
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
txt.print("incr of 1: ")
|
|
||||||
txt.print_uw(&split_warray)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&split_warray[0])
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&split_warray[1])
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&split_warray[2])
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
txt.print("incr of 4 or 5: ")
|
|
||||||
txt.print_uw(&float_array)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&float_array[0])
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&float_array[1])
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(&float_array[2])
|
|
||||||
txt.nl()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ CONTROL FLOW
|
|||||||
------------
|
------------
|
||||||
jump location - continue running at instruction at 'location' (label/memory address)
|
jump location - continue running at instruction at 'location' (label/memory address)
|
||||||
jumpi reg1 - continue running at memory address in reg1 (indirect jump)
|
jumpi reg1 - continue running at memory address in reg1 (indirect jump)
|
||||||
|
preparecall numparams - indicator that the next instructions are the param setup and function call/syscall with <numparams> parameters
|
||||||
call label(argument register list) [: resultreg.type]
|
call label(argument register list) [: resultreg.type]
|
||||||
- calls a subroutine with the given arguments and return value (optional).
|
- calls a subroutine with the given arguments and return value (optional).
|
||||||
save current instruction location+1, continue execution at instruction nr of the label.
|
save current instruction location+1, continue execution at instruction nr of the label.
|
||||||
@ -60,9 +61,11 @@ call label(argument register list) [: resultreg.type]
|
|||||||
If the call is to a rom-routine, 'label' will be a hexadecimal address instead such as $ffd2
|
If the call is to a rom-routine, 'label' will be a hexadecimal address instead such as $ffd2
|
||||||
If the arguments should be passed in CPU registers, they'll have a @REGISTER postfix.
|
If the arguments should be passed in CPU registers, they'll have a @REGISTER postfix.
|
||||||
For example: call $ffd2(r5.b@A)
|
For example: call $ffd2(r5.b@A)
|
||||||
|
Always preceded by parameter setup and preparecall instructions
|
||||||
syscall number (argument register list) [: resultreg.type]
|
syscall number (argument register list) [: resultreg.type]
|
||||||
- do a systemcall identified by number, result value(s) are pushed on value stack by the syscall code so
|
- do a systemcall identified by number, result value(s) are pushed on value stack by the syscall code so
|
||||||
will be POPped off into the given resultregister if any.
|
will be POPped off into the given resultregister if any.
|
||||||
|
Always preceded by parameter setup and preparecall instructions
|
||||||
return - restore last saved instruction location and continue at that instruction. No return value.
|
return - restore last saved instruction location and continue at that instruction. No return value.
|
||||||
returnr reg1 - like return, but also returns the value in reg1 to the caller
|
returnr reg1 - like return, but also returns the value in reg1 to the caller
|
||||||
|
|
||||||
@ -244,6 +247,7 @@ enum class Opcode {
|
|||||||
|
|
||||||
JUMP,
|
JUMP,
|
||||||
JUMPI,
|
JUMPI,
|
||||||
|
PREPARECALL,
|
||||||
CALL,
|
CALL,
|
||||||
SYSCALL,
|
SYSCALL,
|
||||||
RETURN,
|
RETURN,
|
||||||
@ -541,6 +545,7 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"),
|
Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"),
|
||||||
Opcode.JUMP to InstructionFormat.from("N,<a"),
|
Opcode.JUMP to InstructionFormat.from("N,<a"),
|
||||||
Opcode.JUMPI to InstructionFormat.from("N,<r1"),
|
Opcode.JUMPI to InstructionFormat.from("N,<r1"),
|
||||||
|
Opcode.PREPARECALL to InstructionFormat.from("N,<i"),
|
||||||
Opcode.CALL to InstructionFormat.from("N,call"),
|
Opcode.CALL to InstructionFormat.from("N,call"),
|
||||||
Opcode.SYSCALL to InstructionFormat.from("N,syscall"),
|
Opcode.SYSCALL to InstructionFormat.from("N,syscall"),
|
||||||
Opcode.RETURN to InstructionFormat.from("N"),
|
Opcode.RETURN to InstructionFormat.from("N"),
|
||||||
|
@ -213,10 +213,27 @@ class IRProgram(val name: String,
|
|||||||
if(chunk is IRInlineAsmChunk)
|
if(chunk is IRInlineAsmChunk)
|
||||||
require(!chunk.isIR) { "inline IR-asm should have been converted into regular code chunk"}
|
require(!chunk.isIR) { "inline IR-asm should have been converted into regular code chunk"}
|
||||||
}
|
}
|
||||||
chunk.instructions.forEach {
|
chunk.instructions.withIndex().forEach { (index, instr) ->
|
||||||
if(it.labelSymbol!=null && it.opcode in OpcodesThatBranch) {
|
if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) {
|
||||||
if(!it.labelSymbol.startsWith('$') && !it.labelSymbol.first().isDigit())
|
if(!instr.labelSymbol.startsWith('$') && !instr.labelSymbol.first().isDigit())
|
||||||
require(it.branchTarget != null) { "branching instruction to label should have branchTarget set" }
|
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) {
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
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" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,6 +179,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
Opcode.STOREZX -> InsSTOREZX(ins)
|
Opcode.STOREZX -> InsSTOREZX(ins)
|
||||||
Opcode.STOREZI -> InsSTOREZI(ins)
|
Opcode.STOREZI -> InsSTOREZI(ins)
|
||||||
Opcode.JUMP, Opcode.JUMPI -> InsJUMP(ins)
|
Opcode.JUMP, Opcode.JUMPI -> InsJUMP(ins)
|
||||||
|
Opcode.PREPARECALL -> nextPc()
|
||||||
Opcode.CALL -> InsCALL(ins)
|
Opcode.CALL -> InsCALL(ins)
|
||||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||||
Opcode.RETURN -> InsRETURN()
|
Opcode.RETURN -> InsRETURN()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user