ir: JUMPI instruction added to support indirect jumps

This commit is contained in:
Irmen de Jong 2023-07-07 18:25:05 +02:00
parent 90c4b00f74
commit 334d382bfa
6 changed files with 31 additions and 22 deletions

View File

@ -1,9 +1,6 @@
package prog8.codegen.intermediate package prog8.codegen.intermediate
import prog8.code.StMemVar import prog8.code.*
import prog8.code.StNode
import prog8.code.StStaticVariable
import prog8.code.SymbolTable
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.* import prog8.code.core.*
import prog8.intermediate.* import prog8.intermediate.*
@ -1520,17 +1517,26 @@ class IRCodeGen(
private fun translate(jump: PtJump): IRCodeChunks { private fun translate(jump: PtJump): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val instr = if(jump.address!=null) { val chunk = IRCodeChunk(null, null)
IRInstruction(Opcode.JUMPA, address = jump.address!!.toInt()) if(jump.address!=null) {
chunk += IRInstruction(Opcode.JUMP, address = jump.address!!.toInt())
} else { } else {
if (jump.generatedLabel != null) if (jump.generatedLabel != null)
IRInstruction(Opcode.JUMP, labelSymbol = jump.generatedLabel!!) chunk += IRInstruction(Opcode.JUMP, labelSymbol = jump.generatedLabel!!)
else if (jump.identifier != null) else if (jump.identifier != null) {
IRInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.name) val symbol = symbolTable.lookup(jump.identifier!!.name)
if(symbol?.type==StNodeType.MEMVAR || symbol?.type==StNodeType.STATICVAR) {
val jumpReg = registers.nextFree()
chunk += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1 = jumpReg, labelSymbol = jump.identifier!!.name)
chunk += IRInstruction(Opcode.JUMPI, reg1 = jumpReg)
} else {
chunk += IRInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.name)
}
}
else else
throw AssemblyError("weird jump") throw AssemblyError("weird jump")
} }
addInstr(result, instr, null) result += chunk
return result return result
} }

View File

@ -17,10 +17,10 @@ main {
txt.print_ub('a' in name) txt.print_ub('a' in name)
txt.print_ub('e' in name) txt.print_ub('e' in name)
txt.nl() txt.nl()
txt.print_ub(all(othercells)) ;; TODO fix vm ALL() ! txt.print_ub(all(othercells))
txt.print_ub(any(othercells)) txt.print_ub(any(othercells))
othercells[3] = 0 othercells[3] = 0
txt.print_ub(all(othercells)) ;; TODO fix vm ALL() ! txt.print_ub(all(othercells))
txt.print_ub(any(othercells)) txt.print_ub(any(othercells))
reverse(othercells) reverse(othercells)
sort(othercells) sort(othercells)

View File

@ -51,8 +51,8 @@ storezx reg1, address - store zero at memory address, indexed by
CONTROL FLOW CONTROL FLOW
------------ ------------
jump location - continue running at instruction number given by location jump location - continue running at instruction at 'location' (label/memory address)
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction) jumpi reg1 - continue running at memory address in reg1 (indirect jump)
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.
@ -240,7 +240,7 @@ enum class Opcode {
STOREZX, STOREZX,
JUMP, JUMP,
JUMPA, JUMPI,
CALL, CALL,
SYSCALL, SYSCALL,
RETURN, RETURN,
@ -378,14 +378,14 @@ enum class Opcode {
val OpcodesThatJump = setOf( val OpcodesThatJump = setOf(
Opcode.JUMP, Opcode.JUMP,
Opcode.JUMPA, Opcode.JUMPI,
Opcode.RETURN, Opcode.RETURN,
Opcode.RETURNR Opcode.RETURNR
) )
val OpcodesThatBranch = setOf( val OpcodesThatBranch = setOf(
Opcode.JUMP, Opcode.JUMP,
Opcode.JUMPA, Opcode.JUMPI,
Opcode.RETURN, Opcode.RETURN,
Opcode.RETURNR, Opcode.RETURNR,
Opcode.CALL, Opcode.CALL,
@ -514,7 +514,7 @@ val instructionFormats = mutableMapOf(
Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"), Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"),
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.JUMPA to InstructionFormat.from("N,<a"), Opcode.JUMPI to InstructionFormat.from("N,<r1"),
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"),

View File

@ -95,6 +95,7 @@ class IRProgram(val name: String,
} }
} }
} }
result.remove(null)
return result return result
} }
@ -407,6 +408,7 @@ class IRAsmSubroutine(
init { init {
require('.' in label) { "subroutine name is not scoped: $label" } require('.' in label) { "subroutine name is not scoped: $label" }
require(!label.startsWith("main.main.")) { "subroutine name invalid main prefix: $label" } require(!label.startsWith("main.main.")) { "subroutine name invalid main prefix: $label" }
require(label==asmChunk.label)
} }
private val registersUsed by lazy { registersUsedInAssembly(asmChunk.isIR, asmChunk.assembly) } private val registersUsed by lazy { registersUsedInAssembly(asmChunk.isIR, asmChunk.assembly) }

View File

@ -147,6 +147,10 @@ class VirtualMachine(irProgram: IRProgram) {
null -> { null -> {
if(i.address!=null) if(i.address!=null)
throw IllegalArgumentException("vm program can't jump to system memory address (${i.opcode} ${i.address!!.toHex()})") throw IllegalArgumentException("vm program can't jump to system memory address (${i.opcode} ${i.address!!.toHex()})")
else if(i.labelSymbol!=null)
throw IllegalArgumentException("vm program can't jump to system memory address (${i.opcode} ${i.labelSymbol})")
else if(i.reg1!=null)
throw IllegalArgumentException("vm program can't jump to system memory address (${i})")
else else
throw IllegalArgumentException("no branchtarget in $i") throw IllegalArgumentException("no branchtarget in $i")
} }
@ -174,8 +178,7 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.STOREZM -> InsSTOREZM(ins) Opcode.STOREZM -> InsSTOREZM(ins)
Opcode.STOREZX -> InsSTOREZX(ins) Opcode.STOREZX -> InsSTOREZX(ins)
Opcode.STOREZI -> InsSTOREZI(ins) Opcode.STOREZI -> InsSTOREZI(ins)
Opcode.JUMP -> InsJUMP(ins) Opcode.JUMP, Opcode.JUMPI -> InsJUMP(ins)
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
Opcode.CALL -> InsCALL(ins) Opcode.CALL -> InsCALL(ins)
Opcode.SYSCALL -> InsSYSCALL(ins) Opcode.SYSCALL -> InsSYSCALL(ins)
Opcode.RETURN -> InsRETURN() Opcode.RETURN -> InsRETURN()

View File

@ -191,8 +191,6 @@ class VmProgramLoader {
} }
} }
private val functionCallOpcodes = setOf(Opcode.CALL, Opcode.SYSCALL, Opcode.JUMP, Opcode.JUMPA)
private fun varsToMemory( private fun varsToMemory(
program: IRProgram, program: IRProgram,
allocations: VmVariableAllocator, allocations: VmVariableAllocator,