ir/vm: syscall params in high base register to avoid push/pop

This commit is contained in:
Irmen de Jong
2022-11-06 12:40:39 +01:00
parent 469e042216
commit 38efaae7b2
14 changed files with 186 additions and 193 deletions
@@ -71,11 +71,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
if (resultRegister != 0)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
}
return result
@@ -94,11 +94,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
if (resultRegister != 0)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
}
return result
@@ -213,9 +213,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type to reverse")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
}
return result
@@ -235,9 +235,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type to sort")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
}
return result
@@ -10,7 +10,7 @@ import prog8.intermediate.*
internal class ExpressionGen(private val codeGen: IRCodeGen) {
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunks {
require(codeGen.registers.peekNext() > resultRegister)
require(codeGen.registers.peekNext() > resultRegister || resultRegister >= SyscallRegisterBase)
return when (expr) {
is PtMachineRegister -> {
@@ -101,49 +101,33 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
when(iterable.dt) {
DataType.STR -> {
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(check.element, 0, -1)
result += translateExpression(check.iterable, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.STRING_CONTAINS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
result += syscall
result += translateExpression(check.element, SyscallRegisterBase, -1)
result += translateExpression(check.iterable, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.STRING_CONTAINS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
}
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
push += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=2)
result += push
result += translateExpression(check.element, 0, -1)
result += translateExpression(check.iterable, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=2, value = iterable.length!!)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.BYTEARRAY_CONTAINS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=2)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
result += syscall
result += translateExpression(check.element, SyscallRegisterBase, -1)
result += translateExpression(check.iterable, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, value = iterable.length!!)
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.BYTEARRAY_CONTAINS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
}
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
push += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=2)
result += push
result += translateExpression(check.element, 0, -1)
result += translateExpression(check.iterable, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=2, value = iterable.length!!)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.WORDARRAY_CONTAINS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=2)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
result += syscall
result += translateExpression(check.element, SyscallRegisterBase, -1)
result += translateExpression(check.iterable, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, value = iterable.length!!)
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.WORDARRAY_CONTAINS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
}
}
DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported")
else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}")
@@ -332,23 +316,18 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
require(codeGen.registers.peekNext() > 1)
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(binExpr.left, 0, -1)
result += translateExpression(binExpr.right, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=0)
syscall += if(greaterEquals)
IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1=resultRegister, reg2=1)
else
IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1=resultRegister, reg2=1)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
result += syscall
result += translateExpression(binExpr.left, SyscallRegisterBase, -1)
result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = 0)
it += if (greaterEquals)
IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
else
IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
}
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)
@@ -388,23 +367,18 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
require(codeGen.registers.peekNext() > 1)
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(binExpr.left, 0, -1)
result += translateExpression(binExpr.right, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=0)
syscall += if(lessEquals)
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1=resultRegister, reg2=1)
else
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1=resultRegister, reg2=1)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
result += syscall
result += translateExpression(binExpr.left, SyscallRegisterBase, -1)
result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = 0)
it += if (lessEquals)
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
else
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
}
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)
@@ -440,21 +414,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
require(codeGen.registers.peekNext() > 1)
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(binExpr.left, 0, -1)
result += translateExpression(binExpr.right, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0)
if(!notEquals)
syscall += IRInstruction(Opcode.INV, vmDt, reg1=resultRegister)
syscall += IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
result += syscall
result += translateExpression(binExpr.left, SyscallRegisterBase, -1)
result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0)
if (!notEquals)
it += IRInstruction(Opcode.INV, vmDt, reg1 = resultRegister)
it += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value = 1)
}
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)
@@ -1,10 +1,12 @@
package prog8.codegen.intermediate
import prog8.code.core.AssemblyError
import prog8.intermediate.SyscallRegisterBase
internal class RegisterPool {
private var firstFree: Int=3 // integer registers 0,1,2 are reserved
private var firstFreeFloat: Int=0
// reserve 0,1,2 for return values of subroutine calls and syscalls
private var firstFree: Int=3
private var firstFreeFloat: Int=3
fun peekNext() = firstFree
fun peekNextFloat() = firstFreeFloat
@@ -12,7 +14,7 @@ internal class RegisterPool {
fun nextFree(): Int {
val result = firstFree
firstFree++
if(firstFree>65535)
if(firstFree >= SyscallRegisterBase)
throw AssemblyError("out of virtual registers (int)")
return result
}
@@ -20,7 +22,7 @@ internal class RegisterPool {
fun nextFreeFloat(): Int {
val result = firstFreeFloat
firstFreeFloat++
if(firstFreeFloat>65535)
if(firstFreeFloat >= SyscallRegisterBase)
throw AssemblyError("out of virtual registers (fp)")
return result
}