mirror of
https://github.com/irmen/prog8.git
synced 2025-02-01 13:32:51 +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 {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
val bankTr = exprGen.translateExpression(call.args[0])
|
||||
val addressTr = exprGen.translateExpression(call.args[1])
|
||||
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 {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||
val left = exprGen.translateExpression(call.args[0])
|
||||
val right = exprGen.translateExpression(call.args[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")
|
||||
}
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val lengthReg = codeGen.registers.nextFree()
|
||||
@ -167,6 +170,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
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")
|
||||
}
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
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")
|
||||
}
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
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 {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
val type = irType(call.type)
|
||||
val valueTr = exprGen.translateExpression(call.args[0])
|
||||
val minimumTr = exprGen.translateExpression(call.args[1])
|
||||
|
@ -122,6 +122,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
when(check.iterable.type) {
|
||||
DataType.STR -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||
val elementTr = translateExpression(check.element)
|
||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||
val iterableTr = translateExpression(check.iterable)
|
||||
@ -130,6 +131,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
val elementTr = translateExpression(check.element)
|
||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||
val iterableTr = translateExpression(check.iterable)
|
||||
@ -141,6 +143,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
}
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
val elementTr = translateExpression(check.element)
|
||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||
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)) {
|
||||
is StSub -> {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = callTarget.parameters.size), null)
|
||||
// assign the arguments
|
||||
val argRegisters = mutableListOf<FunctionCallArgs.ArgumentSpec>()
|
||||
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)
|
||||
}
|
||||
// create the call
|
||||
val call = IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec))
|
||||
addInstr(result, call, null)
|
||||
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name, fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec)), null)
|
||||
return if(fcall.void)
|
||||
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||
else if(fcall.type==DataType.FLOAT)
|
||||
@ -412,6 +415,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
is StRomSub -> {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = callTarget.parameters.size), null)
|
||||
// assign the arguments
|
||||
val argRegisters = mutableListOf<FunctionCallArgs.ArgumentSpec>()
|
||||
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 irChunks = (result.irProgram.blocks.first().children.single() as IRSubroutine).chunks
|
||||
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.address shouldBe 0x5000
|
||||
}
|
||||
|
@ -1,53 +1,20 @@
|
||||
%import textio
|
||||
%import floats
|
||||
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte[] barray = [11,22,33]
|
||||
uword[] warray = [$1234,$5678,$abcd]
|
||||
uword[] @split split_warray = [$1234,$5678,$abcd]
|
||||
float[] float_array = [11.11,22.22,33.33]
|
||||
ubyte arg3 = 200
|
||||
uword result = calc(101, 202, arg3)
|
||||
txt.print_uw(result)
|
||||
|
||||
txt.print("incr of 1: ")
|
||||
txt.print_uw(&barray)
|
||||
txt.spc()
|
||||
txt.print_uw(&barray[0])
|
||||
txt.spc()
|
||||
txt.print_uw(&barray[1])
|
||||
txt.spc()
|
||||
txt.print_uw(&barray[2])
|
||||
txt.nl()
|
||||
str name = "irmen"
|
||||
ubyte[] array = [1,2,3,4]
|
||||
bool xx = 44 in array
|
||||
bool yy = 'a' in name
|
||||
}
|
||||
|
||||
txt.print("incr of 2: ")
|
||||
txt.print_uw(&warray)
|
||||
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()
|
||||
sub calc(ubyte a1, ubyte a2, ubyte a3) -> uword {
|
||||
return a1 as uword + a2 + a3
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ CONTROL FLOW
|
||||
------------
|
||||
jump location - continue running at instruction at 'location' (label/memory address)
|
||||
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]
|
||||
- calls a subroutine with the given arguments and return value (optional).
|
||||
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 arguments should be passed in CPU registers, they'll have a @REGISTER postfix.
|
||||
For example: call $ffd2(r5.b@A)
|
||||
Always preceded by parameter setup and preparecall instructions
|
||||
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
|
||||
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.
|
||||
returnr reg1 - like return, but also returns the value in reg1 to the caller
|
||||
|
||||
@ -244,6 +247,7 @@ enum class Opcode {
|
||||
|
||||
JUMP,
|
||||
JUMPI,
|
||||
PREPARECALL,
|
||||
CALL,
|
||||
SYSCALL,
|
||||
RETURN,
|
||||
@ -541,6 +545,7 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.STOREZX to InstructionFormat.from("BW,<r1,>a | F,<r1,>a"),
|
||||
Opcode.JUMP to InstructionFormat.from("N,<a"),
|
||||
Opcode.JUMPI to InstructionFormat.from("N,<r1"),
|
||||
Opcode.PREPARECALL to InstructionFormat.from("N,<i"),
|
||||
Opcode.CALL to InstructionFormat.from("N,call"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,syscall"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
|
@ -213,10 +213,27 @@ class IRProgram(val name: String,
|
||||
if(chunk is IRInlineAsmChunk)
|
||||
require(!chunk.isIR) { "inline IR-asm should have been converted into regular code chunk"}
|
||||
}
|
||||
chunk.instructions.forEach {
|
||||
if(it.labelSymbol!=null && it.opcode in OpcodesThatBranch) {
|
||||
if(!it.labelSymbol.startsWith('$') && !it.labelSymbol.first().isDigit())
|
||||
require(it.branchTarget != null) { "branching instruction to label should have branchTarget set" }
|
||||
chunk.instructions.withIndex().forEach { (index, instr) ->
|
||||
if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) {
|
||||
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) {
|
||||
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.STOREZI -> InsSTOREZI(ins)
|
||||
Opcode.JUMP, Opcode.JUMPI -> InsJUMP(ins)
|
||||
Opcode.PREPARECALL -> nextPc()
|
||||
Opcode.CALL -> InsCALL(ins)
|
||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||
Opcode.RETURN -> InsRETURN()
|
||||
|
Loading…
x
Reference in New Issue
Block a user