vm syscall instruction no longer fixed to r0

This commit is contained in:
Irmen de Jong 2023-04-10 13:44:05 +02:00
parent 5196443b26
commit ac21e1be5c
13 changed files with 52 additions and 49 deletions

View File

@ -74,10 +74,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])
val targetReg = codeGen.registers.nextFree()
addToResult(result, left, 65500, -1)
addToResult(result, right, 65501, -1)
addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null)
addInstr(result, IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=targetReg, reg2=0), null)
addToResult(result, left, SyscallRegisterBase, -1)
addToResult(result, right, SyscallRegisterBase+1, -1)
addInstr(result, IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=targetReg, immediate = IMSyscall.COMPARE_STRINGS.number), null)
return ExpressionCodeResult(result, IRDataType.BYTE, targetReg, -1)
}
@ -111,10 +110,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
addToResult(result, tr, SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
// SysCall call convention: return value in register r0
if(tr.resultReg!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = tr.resultReg, reg2 = 0)
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=tr.resultReg, immediate = syscall.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1)
}
@ -136,10 +132,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
addToResult(result, tr, SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
// SysCall call convention: return value in register r0
if(tr.resultReg!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = tr.resultReg, reg2 = 0)
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=tr.resultReg, immediate = syscall.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1)
}

View File

@ -116,8 +116,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addToResult(result, tr, SyscallRegisterBase+1, -1)
val resultReg = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0)
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.STRING_CONTAINS.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
@ -129,8 +128,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val resultReg = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!)
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0)
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.BYTEARRAY_CONTAINS.number)
}
// SysCall call convention: return value in register r0
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
@ -143,8 +141,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val resultReg = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!)
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0)
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.WORDARRAY_CONTAINS.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
@ -469,8 +466,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val rightTr = translateExpression(binExpr.right)
addToResult(result, rightTr, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number)
// SysCall call convention: return value in register r0
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1 = leftTr.resultReg, immediate = IMSyscall.COMPARE_STRINGS.number)
val zeroReg = codeGen.registers.nextFree()
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = zeroReg, immediate = 0)
it += if (greaterEquals)
@ -524,17 +520,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addToResult(result, leftTr, SyscallRegisterBase, -1)
val rightTr = translateExpression(binExpr.right)
addToResult(result, rightTr, SyscallRegisterBase+1, -1)
val resultReg = codeGen.registers.nextFree()
val resultReg = codeGen.registers.nextFree() // TODO reuse leftTr resultreg?
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number)
// SysCall call convention: return value in register r0
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultReg, immediate = IMSyscall.COMPARE_STRINGS.number)
val zeroReg = codeGen.registers.nextFree()
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = zeroReg, immediate = 0)
it += if (lessEquals)
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1 = 0, reg2 = zeroReg)
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1 = resultReg, reg2 = zeroReg)
else
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1 = 0, reg2 = zeroReg)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultReg, reg2=0)
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1 = resultReg, reg2 = zeroReg)
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
} else {
@ -581,11 +575,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addToResult(result, rightTr, SyscallRegisterBase+1, -1)
val resultRegister = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number)
// SysCall call convention: return value in register r0
it += IRInstruction(Opcode.SYSCALLR, IRDataType.BYTE, reg1=resultRegister, immediate = IMSyscall.COMPARE_STRINGS.number)
if (!notEquals)
it += IRInstruction(Opcode.INV, vmDt, reg1 = 0)
it += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0)
it += IRInstruction(Opcode.INV, vmDt, reg1 = resultRegister)
it += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, immediate = 1)
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)

View File

@ -5,7 +5,7 @@ import prog8.intermediate.SyscallRegisterBase
internal class RegisterPool {
// reserve 0,1,2 for return values of subroutine calls and syscalls
// TODO set this back to 0 once 'resultRegister' has been removed everywhere and SYSCALL/DIVMOD fixed?
// TODO set this back to 0 once 'resultRegister' has been removed everywhere and DIVMOD fixed to not use r0?
private var firstFree: Int=3
private var firstFreeFloat: Int=3

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 r65500,conv.str2uword.string
syscall 11
syscallr.w r0,11
returnreg.w r0
}}
}
@ -208,7 +208,7 @@ sub str2word(str string) -> word {
; (any non-digit character will terminate the number string that is parsed)
%ir {{
loadm.w r65500,conv.str2word.string
syscall 12
syscallr.w r0,12
returnreg.w r0
}}
}

View File

@ -126,7 +126,7 @@ sub ceil(float value) -> float {
sub rndf() -> float {
%ir {{
syscall 35
syscallr.f fr0,35
returnreg.f fr0
}}
}

View File

@ -161,14 +161,14 @@ math {
sub rnd() -> ubyte {
%ir {{
syscall 33
syscallr.b r0,33
returnreg.b r0
}}
}
sub rndw() -> uword {
%ir {{
syscall 34
syscallr.w r0,34
returnreg.w r0
}}
}

View File

@ -86,7 +86,7 @@ string {
%ir {{
loadm.w r65500,string.compare.st1
loadm.w r65501,string.compare.st2
syscall 29
syscallr.b r0,29
returnreg.b r0
}}
}

View File

@ -107,7 +107,7 @@ sys {
%ir {{
loadm.w r65500,sys.gfx_getpixel.xx
loadm.w r65501,sys.gfx_getpixel.yy
syscall 30
syscallr.b r0,30
returnreg.b r0
}}
}

View File

@ -123,7 +123,7 @@ sub input_chars (uword buffer) -> ubyte {
; It assumes the keyboard is selected as I/O channel!
%ir {{
loadm.w r65500,txt.input_chars.buffer
syscall 6
syscallr.b r0,6
returnreg.b r0
}}
}

View File

@ -52,7 +52,8 @@ jump location - continue running at instruction number g
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. Expect no return value.
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, no result value
syscallr reg1, value - do a systemcall identified by call number, result value is set into reg1
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
@ -237,6 +238,7 @@ enum class Opcode {
CALL,
CALLRVAL,
SYSCALL,
SYSCALLR,
RETURN,
RETURNREG,
@ -386,6 +388,7 @@ val OpcodesThatBranch = setOf(
Opcode.CALL,
Opcode.CALLRVAL,
Opcode.SYSCALL,
Opcode.SYSCALLR,
Opcode.BSTCC,
Opcode.BSTCS,
Opcode.BSTEQ,
@ -517,6 +520,7 @@ val instructionFormats = mutableMapOf(
Opcode.CALL to InstructionFormat.from("N,<a"),
Opcode.CALLRVAL to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
Opcode.SYSCALLR to InstructionFormat.from("BW,>r1,<i | F,>fr1,<i"),
Opcode.RETURN to InstructionFormat.from("N"),
Opcode.RETURNREG to InstructionFormat.from("BW,>r1 | F,>fr1"),
Opcode.BSTCC to InstructionFormat.from("N,<a"),
@ -695,7 +699,7 @@ 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 && opcode!=Opcode.SYSCALLR) require(immediateFp !=null) {"missing immediate fp value"}
else require(immediate!=null || labelSymbol!=null) {"missing immediate value or labelsymbol"}
}
if(type!=IRDataType.FLOAT)
@ -703,10 +707,12 @@ data class IRInstruction(
if(format.address!=OperandDirection.UNUSED)
require(address!=null || labelSymbol!=null) {"missing an address or labelsymbol"}
if(format.immediate && (immediate!=null || immediateFp!=null)) {
when (type) {
IRDataType.BYTE -> require(immediate in -128..255) {"immediate value out of range for byte: $immediate"}
IRDataType.WORD -> require(immediate in -32768..65535) {"immediate value out of range for word: $immediate"}
IRDataType.FLOAT, null -> {}
if(opcode!=Opcode.SYSCALL && opcode!=Opcode.SYSCALLR) {
when (type) {
IRDataType.BYTE -> require(immediate in -128..255) { "immediate value out of range for byte: $immediate" }
IRDataType.WORD -> require(immediate in -32768..65535) { "immediate value out of range for word: $immediate" }
IRDataType.FLOAT, null -> {}
}
}
}
reg1direction = format.reg1
@ -725,6 +731,12 @@ data class IRInstruction(
else
require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"}
}
if(opcode==Opcode.SYSCALL || opcode==Opcode.SYSCALLR) {
require(immediate!=null) {
"syscall needs immediate integer for the syscall number"
}
}
}
fun addUsedRegistersCounts(

View File

@ -182,7 +182,7 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, placeholder
throw IRParseException("invalid fpReg1 for $line")
if(format.fpReg2==OperandDirection.UNUSED && fpReg2!=null)
throw IRParseException("invalid fpReg2 for $line")
if(format.immediate) {
if(format.immediate && opcode!=Opcode.SYSCALL && opcode!=Opcode.SYSCALLR) {
if(immediateInt==null && immediateFp==null && labelSymbol==null)
throw IRParseException("needs value or symbol for $line")
when (type) {
@ -222,5 +222,10 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, placeholder
return left(IRInstruction(opcode, type, reg1, labelSymbol = reg))
}
if(opcode==Opcode.SYSCALLR && type==IRDataType.FLOAT) {
immediateInt = immediateFp!!.toInt()
immediateFp = null
}
return left(IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, immediateInt, immediateFp, address, labelSymbol = labelSymbol))
}

View File

@ -178,7 +178,8 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
Opcode.CALL -> InsCALL(ins)
Opcode.CALLRVAL -> InsCALLRVAL(ins)
Opcode.SYSCALL -> InsSYSCALL(ins)
Opcode.SYSCALL -> InsSYSCALL(ins, false)
Opcode.SYSCALLR -> InsSYSCALL(ins, true)
Opcode.RETURN -> InsRETURN()
Opcode.RETURNREG -> InsRETURNREG(ins)
Opcode.BSTCC -> InsBSTCC(ins)
@ -360,7 +361,7 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsSYSCALL(i: IRInstruction) {
private fun InsSYSCALL(i: IRInstruction, hasReturnReg: Boolean) {
val call = Syscall.values()[i.immediate!!]
SysCalls.call(call, this)
nextPc()

View File

@ -100,7 +100,7 @@ class VmProgramLoader {
private fun pass2translateSyscalls(chunks: MutableList<IRCodeChunk>) {
chunks.forEach { chunk ->
chunk.instructions.withIndex().forEach { (index, ins) ->
if(ins.opcode == Opcode.SYSCALL) {
if(ins.opcode == Opcode.SYSCALL || ins.opcode==Opcode.SYSCALLR) {
// convert IR Syscall to VM Syscall
val vmSyscall = when(ins.immediate!!) {
IMSyscall.SORT_UBYTE.number -> Syscall.SORT_UBYTE