mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
tweak IR call args setting now via special SETPARAM instruction
This commit is contained in:
parent
b55be093be
commit
efd7d6f0c0
@ -82,9 +82,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
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)
|
||||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=left.resultReg), null)
|
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1=left.resultReg, immediate = 0), null)
|
||||||
addToResult(result, right, right.resultReg, -1)
|
addToResult(result, right, right.resultReg, -1)
|
||||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=right.resultReg), null)
|
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1=right.resultReg, immediate = 1), null)
|
||||||
addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null)
|
addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null)
|
||||||
addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=left.resultReg), null)
|
addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=left.resultReg), null)
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, left.resultReg, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, left.resultReg, -1)
|
||||||
@ -119,9 +119,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
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)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||||
}
|
}
|
||||||
@ -144,9 +144,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
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)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||||
}
|
}
|
||||||
@ -272,9 +272,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
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)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||||
}
|
}
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||||
@ -297,9 +297,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
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)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, reg1 = tr.resultReg, immediate = 0)
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = if(array.dt==DataType.STR) array.length!!-1 else array.length)
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, reg1 = tr.resultReg, immediate = 1)
|
||||||
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
|
||||||
}
|
}
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||||
|
@ -112,10 +112,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
DataType.STR -> {
|
DataType.STR -> {
|
||||||
tr = translateExpression(check.element)
|
tr = translateExpression(check.element)
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
|
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 0), null)
|
||||||
tr = translateExpression(check.iterable)
|
tr = translateExpression(check.iterable)
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
|
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1), null)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number)
|
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number)
|
||||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||||
@ -125,13 +125,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||||
tr = translateExpression(check.element)
|
tr = translateExpression(check.element)
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
|
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 0), null)
|
||||||
tr = translateExpression(check.iterable)
|
tr = translateExpression(check.iterable)
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1)
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 2)
|
||||||
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number)
|
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number)
|
||||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||||
}
|
}
|
||||||
@ -141,13 +141,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||||
tr = translateExpression(check.element)
|
tr = translateExpression(check.element)
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
|
addInstr(result, IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 0), null)
|
||||||
tr = translateExpression(check.iterable)
|
tr = translateExpression(check.iterable)
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addToResult(result, tr, tr.resultReg, -1)
|
||||||
result += IRCodeChunk(null, null).also {
|
result += IRCodeChunk(null, null).also {
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.WORD, tr.resultReg, immediate = 1)
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
|
it += IRInstruction(Opcode.SETPARAM, IRDataType.BYTE, tr.resultReg, immediate = 2)
|
||||||
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number)
|
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number)
|
||||||
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
|
||||||
}
|
}
|
||||||
@ -358,23 +358,33 @@ 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>()
|
||||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
for ((index, argspec) in fcall.args.zip(callTarget.parameters).withIndex()) {
|
||||||
val paramDt = codeGen.irType(parameter.type)
|
val (arg, param) = argspec
|
||||||
val symbol = "${fcall.name}.${parameter.name}"
|
val paramDt = codeGen.irType(param.type)
|
||||||
if(codeGen.isZero(arg)) {
|
|
||||||
addInstr(result, IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol), null)
|
|
||||||
} else {
|
|
||||||
if (paramDt == IRDataType.FLOAT) {
|
|
||||||
val tr = translateExpression(arg)
|
val tr = translateExpression(arg)
|
||||||
addToResult(result, tr, -1, tr.resultFpReg)
|
result += tr.chunks
|
||||||
addInstr(result, IRInstruction(Opcode.STOREM, paramDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol), null)
|
if(paramDt==IRDataType.FLOAT)
|
||||||
} else {
|
addInstr(result, IRInstruction(Opcode.SETPARAM, paramDt, fpReg1 = tr.resultFpReg, immediate = index), null)
|
||||||
val tr = translateExpression(arg)
|
else
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
addInstr(result, IRInstruction(Opcode.SETPARAM, paramDt, reg1 = tr.resultReg, immediate = index), null)
|
||||||
addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1 = tr.resultReg, labelSymbol = symbol), null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||||
|
// val paramDt = codeGen.irType(parameter.type)
|
||||||
|
// val symbol = "${fcall.name}.${parameter.name}"
|
||||||
|
// if(codeGen.isZero(arg)) {
|
||||||
|
// addInstr(result, IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol), null)
|
||||||
|
// } else {
|
||||||
|
// if (paramDt == IRDataType.FLOAT) {
|
||||||
|
// val tr = translateExpression(arg)
|
||||||
|
// addToResult(result, tr, -1, tr.resultFpReg)
|
||||||
|
// addInstr(result, IRInstruction(Opcode.STOREM, paramDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol), null)
|
||||||
|
// } else {
|
||||||
|
// val tr = translateExpression(arg)
|
||||||
|
// addToResult(result, tr, tr.resultReg, -1)
|
||||||
|
// addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1 = tr.resultReg, labelSymbol = symbol), null)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
return if(fcall.void) {
|
return if(fcall.void) {
|
||||||
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name), null)
|
addInstr(result, IRInstruction(Opcode.CALL, labelSymbol = fcall.name), null)
|
||||||
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||||
|
@ -197,7 +197,7 @@ sub str2uword(str string) -> uword {
|
|||||||
; (any non-digit character will terminate the number string that is parsed)
|
; (any non-digit character will terminate the number string that is parsed)
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,conv.str2uword.string
|
loadm.w r65535,conv.str2uword.string
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
syscall 11
|
syscall 11
|
||||||
pop.w r0
|
pop.w r0
|
||||||
returnr.w r0
|
returnr.w r0
|
||||||
@ -210,7 +210,7 @@ sub str2word(str string) -> word {
|
|||||||
; (any non-digit character will terminate the number string that is parsed)
|
; (any non-digit character will terminate the number string that is parsed)
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,conv.str2word.string
|
loadm.w r65535,conv.str2word.string
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
syscall 12
|
syscall 12
|
||||||
pop.w r0
|
pop.w r0
|
||||||
returnr.w r0
|
returnr.w r0
|
||||||
|
@ -11,7 +11,7 @@ sub print_f(float value) {
|
|||||||
; ---- prints the floating point value (without a newline).
|
; ---- prints the floating point value (without a newline).
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr65535,floats.print_f.value
|
loadm.f fr65535,floats.print_f.value
|
||||||
push.f fr65535
|
setparam.f fr65535,0
|
||||||
syscall 25
|
syscall 25
|
||||||
return
|
return
|
||||||
}}
|
}}
|
||||||
@ -136,7 +136,7 @@ sub rndf() -> float {
|
|||||||
sub rndseedf(float seed) {
|
sub rndseedf(float seed) {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.f fr65535,floats.rndseedf.seed
|
loadm.f fr65535,floats.rndseedf.seed
|
||||||
push.f fr65535
|
setparam.f fr65535,0
|
||||||
syscall 32
|
syscall 32
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -179,9 +179,9 @@ math {
|
|||||||
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
|
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,math.rndseed.seed1
|
loadm.w r65535,math.rndseed.seed1
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
loadm.w r65535,math.rndseed.seed2
|
loadm.w r65535,math.rndseed.seed2
|
||||||
push.w r65535
|
setparam.w r65535,1
|
||||||
syscall 31
|
syscall 31
|
||||||
return
|
return
|
||||||
}}
|
}}
|
||||||
|
@ -85,9 +85,9 @@ string {
|
|||||||
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
|
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,string.compare.st1
|
loadm.w r65535,string.compare.st1
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
loadm.w r65535,string.compare.st2
|
loadm.w r65535,string.compare.st2
|
||||||
push.w r65535
|
setparam.w r65535,1
|
||||||
syscall 29
|
syscall 29
|
||||||
pop.b r0
|
pop.b r0
|
||||||
returnr.b r0
|
returnr.b r0
|
||||||
|
@ -16,7 +16,7 @@ sys {
|
|||||||
; --- wait approximately the given number of jiffies (1/60th seconds)
|
; --- wait approximately the given number of jiffies (1/60th seconds)
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,sys.wait.jiffies
|
loadm.w r65535,sys.wait.jiffies
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
syscall 13
|
syscall 13
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ sys {
|
|||||||
; -- immediately exit the program with a return code in the A register
|
; -- immediately exit the program with a return code in the A register
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.b r65535,sys.exit.returnvalue
|
loadm.b r65535,sys.exit.returnvalue
|
||||||
push.b r65535
|
setparam.b r65535,0
|
||||||
syscall 1
|
syscall 1
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ sys {
|
|||||||
sub gfx_enable(ubyte mode) {
|
sub gfx_enable(ubyte mode) {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.b r65535,sys.gfx_enable.mode
|
loadm.b r65535,sys.gfx_enable.mode
|
||||||
push.b r65535
|
setparam.b r65535,0
|
||||||
syscall 8
|
syscall 8
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ sys {
|
|||||||
sub gfx_clear(ubyte color) {
|
sub gfx_clear(ubyte color) {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.b r65535,sys.gfx_clear.color
|
loadm.b r65535,sys.gfx_clear.color
|
||||||
push.b r65535
|
setparam.b r65535,0
|
||||||
syscall 9
|
syscall 9
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -101,11 +101,11 @@ sys {
|
|||||||
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,sys.gfx_plot.xx
|
loadm.w r65535,sys.gfx_plot.xx
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
loadm.w r65535,sys.gfx_plot.yy
|
loadm.w r65535,sys.gfx_plot.yy
|
||||||
push.w r65535
|
setparam.w r65535,1
|
||||||
loadm.b r65535,sys.gfx_plot.color
|
loadm.b r65535,sys.gfx_plot.color
|
||||||
push.b r65535
|
setparam.b r65535,2
|
||||||
syscall 10
|
syscall 10
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -113,9 +113,9 @@ sys {
|
|||||||
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,sys.gfx_getpixel.xx
|
loadm.w r65535,sys.gfx_getpixel.xx
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
loadm.w r65535,sys.gfx_getpixel.yy
|
loadm.w r65535,sys.gfx_getpixel.yy
|
||||||
push.w r65535
|
setparam.w r65535,1
|
||||||
syscall 30
|
syscall 30
|
||||||
pop.b r0
|
pop.b r0
|
||||||
returnr.b r0
|
returnr.b r0
|
||||||
|
@ -16,7 +16,7 @@ sub clear_screen() {
|
|||||||
str @shared sequence = "\x1b[2J\x1B[H"
|
str @shared sequence = "\x1b[2J\x1B[H"
|
||||||
%ir {{
|
%ir {{
|
||||||
load.w r65535,txt.clear_screen.sequence
|
load.w r65535,txt.clear_screen.sequence
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
syscall 3
|
syscall 3
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ sub uppercase() {
|
|||||||
sub chrout(ubyte char) {
|
sub chrout(ubyte char) {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.b r65535,txt.chrout.char
|
loadm.b r65535,txt.chrout.char
|
||||||
push.b r65535
|
setparam.b r65535,0
|
||||||
syscall 2
|
syscall 2
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ sub chrout(ubyte char) {
|
|||||||
sub print (str text) {
|
sub print (str text) {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,txt.print.text
|
loadm.w r65535,txt.print.text
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
syscall 3
|
syscall 3
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -126,9 +126,9 @@ sub input_chars (uword buffer) -> ubyte {
|
|||||||
; It assumes the keyboard is selected as I/O channel!
|
; It assumes the keyboard is selected as I/O channel!
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r65535,txt.input_chars.buffer
|
loadm.w r65535,txt.input_chars.buffer
|
||||||
push.w r65535
|
setparam.w r65535,0
|
||||||
load.b r65535,80
|
load.b r65535,80
|
||||||
push.b r65535
|
setparam.b r65535,1
|
||||||
syscall 6
|
syscall 6
|
||||||
pop.b r0
|
pop.b r0
|
||||||
returnr.b r0
|
returnr.b r0
|
||||||
|
@ -47,9 +47,6 @@ Compiler:
|
|||||||
- ir: peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out! and don't renumber registers above SyscallRegisterBase!)
|
- ir: peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out! and don't renumber registers above SyscallRegisterBase!)
|
||||||
- ir: add more optimizations in IRPeepholeOptimizer
|
- ir: add more optimizations in IRPeepholeOptimizer
|
||||||
- ir: for expressions with array indexes that occur multiple times, can we avoid loading them into new virtualregs everytime and just reuse a single virtualreg as indexer? (simple form of common subexpression elimination)
|
- ir: for expressions with array indexes that occur multiple times, can we avoid loading them into new virtualregs everytime and just reuse a single virtualreg as indexer? (simple form of common subexpression elimination)
|
||||||
- ir: write arguments for subroutine calls in IR differently?
|
|
||||||
don't load them explicitly into the variables but use a new special instruction to do it transparently.
|
|
||||||
(vm should take care of it based on the subroutine's parameter list)
|
|
||||||
- PtAst/IR: more complex common subexpression eliminations
|
- PtAst/IR: more complex common subexpression eliminations
|
||||||
- vm: somehow be able to load a label address as value? (VmProgramLoader) this may require storing the program as bytecodes in actual memory though...
|
- vm: somehow be able to load a label address as value? (VmProgramLoader) this may require storing the program as bytecodes in actual memory though...
|
||||||
- 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition.
|
- 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition.
|
||||||
|
@ -4,18 +4,24 @@
|
|||||||
%import string
|
%import string
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
ubyte a
|
||||||
|
sub func1() {
|
||||||
|
a++
|
||||||
|
}
|
||||||
|
|
||||||
|
sub func2() -> ubyte {
|
||||||
|
a++
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
str name = "irmen"
|
a=42
|
||||||
reverse(name)
|
func1()
|
||||||
txt.print(name)
|
txt.print_ub(a)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
sort(name)
|
txt.print_ub(func2())
|
||||||
txt.print(name)
|
|
||||||
txt.nl()
|
|
||||||
txt.print_ub('@' in name)
|
|
||||||
txt.nl()
|
|
||||||
txt.print_ub('i' in name)
|
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
floats.print_f(floats.PI)
|
||||||
sys.wait(60)
|
sys.wait(60)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ CONTROL FLOW
|
|||||||
------------
|
------------
|
||||||
jump location - continue running at instruction number given by location
|
jump location - continue running at instruction number given by location
|
||||||
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
|
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
|
||||||
|
setparam reg1, argpos - sets reg1 as the value for the parameter in the given position for an upcoming function call (call, callr, syscall, or even jump opcode).
|
||||||
call location - save current instruction location+1, continue execution at instruction nr given by location. No return value is expected.
|
call location - save current instruction location+1, continue execution at instruction nr given by location. No return value is expected.
|
||||||
callr reg1, location - like call but expects the routine to return a value with a returnr instruction, it then puts that in reg1
|
callr reg1, location - like call but expects the routine to return a value with a returnr instruction, it then puts that in reg1
|
||||||
syscall value - do a systemcall identified by call number, result value(s) are pushed on value stack so need to be POPped off (depends on syscall)
|
syscall value - do a systemcall identified by call number, result value(s) are pushed on value stack so need to be POPped off (depends on syscall)
|
||||||
@ -237,6 +238,7 @@ enum class Opcode {
|
|||||||
|
|
||||||
JUMP,
|
JUMP,
|
||||||
JUMPA,
|
JUMPA,
|
||||||
|
SETPARAM,
|
||||||
CALL,
|
CALL,
|
||||||
CALLR,
|
CALLR,
|
||||||
SYSCALL,
|
SYSCALL,
|
||||||
@ -517,6 +519,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.JUMPA to InstructionFormat.from("N,<a"),
|
Opcode.JUMPA to InstructionFormat.from("N,<a"),
|
||||||
|
Opcode.SETPARAM to InstructionFormat.from("BW,<r1,<i | F,<fr1,<i"),
|
||||||
Opcode.CALL to InstructionFormat.from("N,<a"),
|
Opcode.CALL to InstructionFormat.from("N,<a"),
|
||||||
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
|
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
|
||||||
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
|
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
|
||||||
@ -698,7 +701,12 @@ data class IRInstruction(
|
|||||||
if(format.fpReg1==OperandDirection.UNUSED) require(fpReg1==null) { "invalid fpReg1" }
|
if(format.fpReg1==OperandDirection.UNUSED) require(fpReg1==null) { "invalid fpReg1" }
|
||||||
if(format.fpReg2==OperandDirection.UNUSED) require(fpReg2==null) { "invalid fpReg2" }
|
if(format.fpReg2==OperandDirection.UNUSED) require(fpReg2==null) { "invalid fpReg2" }
|
||||||
if(format.immediate) {
|
if(format.immediate) {
|
||||||
if(type==IRDataType.FLOAT) require(immediateFp !=null) {"missing immediate fp value"}
|
if(type==IRDataType.FLOAT) {
|
||||||
|
if(opcode!=Opcode.SETPARAM)
|
||||||
|
require(immediateFp !=null) {"missing immediate fp value"}
|
||||||
|
else
|
||||||
|
require(immediateFp==null) {"setparam never has immediateFp only immediate"}
|
||||||
|
}
|
||||||
else require(immediate!=null || labelSymbol!=null) {"missing immediate value or labelsymbol"}
|
else require(immediate!=null || labelSymbol!=null) {"missing immediate value or labelsymbol"}
|
||||||
}
|
}
|
||||||
if(type!=IRDataType.FLOAT)
|
if(type!=IRDataType.FLOAT)
|
||||||
|
@ -198,6 +198,10 @@ fun parseIRCodeLine(line: String, location: Pair<IRCodeChunk, Int>?, placeholder
|
|||||||
null -> {}
|
null -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(format.immediate && opcode==Opcode.SETPARAM && immediateInt==null) {
|
||||||
|
immediateInt = immediateFp!!.toInt()
|
||||||
|
immediateFp = null
|
||||||
|
}
|
||||||
|
|
||||||
if(format.address!=OperandDirection.UNUSED && address==null && labelSymbol==null)
|
if(format.address!=OperandDirection.UNUSED && address==null && labelSymbol==null)
|
||||||
throw IRParseException("requires address or symbol for $line")
|
throw IRParseException("requires address or symbol for $line")
|
||||||
|
@ -92,6 +92,7 @@ uword sys.wait.jiffies
|
|||||||
</PARAMS>
|
</PARAMS>
|
||||||
<INLINEASM LABEL="sys.wait" IR="true" POS="[library:/prog8lib/virtual/syslib.p8: line 17 col 10-13]">
|
<INLINEASM LABEL="sys.wait" IR="true" POS="[library:/prog8lib/virtual/syslib.p8: line 17 col 10-13]">
|
||||||
loadm.w r0,sys.wait.jiffies
|
loadm.w r0,sys.wait.jiffies
|
||||||
|
setparam.w r0,0
|
||||||
syscall 13
|
syscall 13
|
||||||
</INLINEASM>
|
</INLINEASM>
|
||||||
<CODE>
|
<CODE>
|
||||||
|
@ -80,7 +80,12 @@ enum class Syscall {
|
|||||||
RNDF,
|
RNDF,
|
||||||
STRING_CONTAINS,
|
STRING_CONTAINS,
|
||||||
BYTEARRAY_CONTAINS,
|
BYTEARRAY_CONTAINS,
|
||||||
WORDARRAY_CONTAINS
|
WORDARRAY_CONTAINS;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val VALUES = values()
|
||||||
|
fun fromInt(value: Int) = VALUES[value]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object SysCalls {
|
object SysCalls {
|
||||||
|
@ -176,6 +176,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
Opcode.STOREZI -> InsSTOREZI(ins)
|
Opcode.STOREZI -> InsSTOREZI(ins)
|
||||||
Opcode.JUMP -> InsJUMP(ins)
|
Opcode.JUMP -> InsJUMP(ins)
|
||||||
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
|
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
|
||||||
|
Opcode.SETPARAM -> InsSETPARAM(ins)
|
||||||
Opcode.CALL, Opcode.CALLR -> InsCALL(ins)
|
Opcode.CALL, Opcode.CALLR -> InsCALL(ins)
|
||||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||||
Opcode.RETURN -> InsRETURN()
|
Opcode.RETURN -> InsRETURN()
|
||||||
@ -351,8 +352,19 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun InsSYSCALL(i: IRInstruction) {
|
private fun InsSYSCALL(i: IRInstruction) {
|
||||||
val call = Syscall.values()[i.immediate!!]
|
// put the syscall's arguments that were prepared onto the stack
|
||||||
SysCalls.call(call, this) // note: any result value(s) are pushed on the value stack
|
for(value in syscallParams) {
|
||||||
|
if(value.dt==null)
|
||||||
|
break
|
||||||
|
when(value.dt!!) {
|
||||||
|
IRDataType.BYTE -> valueStack.push(value.value as UByte)
|
||||||
|
IRDataType.WORD -> valueStack.pushw(value.value as UShort)
|
||||||
|
IRDataType.FLOAT -> valueStack.pushf(value.value as Float)
|
||||||
|
}
|
||||||
|
value.dt=null
|
||||||
|
}
|
||||||
|
val call = Syscall.fromInt(i.immediate!!)
|
||||||
|
SysCalls.call(call, this) // note: any result value(s) are pushed back on the value stack
|
||||||
nextPc()
|
nextPc()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,6 +601,31 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
branchTo(i)
|
branchTo(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SyscallParamValue(var dt: IRDataType?, var value: Comparable<*>?)
|
||||||
|
private val syscallParams = Array(100) { SyscallParamValue(null, null) }
|
||||||
|
|
||||||
|
private fun InsSETPARAM(i: IRInstruction) {
|
||||||
|
// store the argument value into the retrieved subroutine's parameter variable (already cached in the instruction's address)
|
||||||
|
// the reason this is a special instruction is to be flexible in implementing the call convention
|
||||||
|
val address = i.address
|
||||||
|
if(address==null) {
|
||||||
|
// this param is for a SYSCALL (that has no param variable address, instead it goes via the stack)
|
||||||
|
syscallParams[i.immediate!!].dt = i.type!!
|
||||||
|
syscallParams[i.immediate!!].value = when(i.type!!) {
|
||||||
|
IRDataType.BYTE -> registers.getUB(i.reg1!!)
|
||||||
|
IRDataType.WORD -> registers.getUW(i.reg1!!)
|
||||||
|
IRDataType.FLOAT -> registers.getFloat(i.fpReg1!!)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when (i.type!!) {
|
||||||
|
IRDataType.BYTE -> memory.setUB(address, registers.getUB(i.reg1!!))
|
||||||
|
IRDataType.WORD -> memory.setUW(address, registers.getUW(i.reg1!!))
|
||||||
|
IRDataType.FLOAT -> memory.setFloat(address, registers.getFloat(i.fpReg1!!))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextPc()
|
||||||
|
}
|
||||||
|
|
||||||
private fun InsCALL(i: IRInstruction) {
|
private fun InsCALL(i: IRInstruction) {
|
||||||
callStack.push(CallSiteContext(pcChunk, pcIndex+1, i.reg1, i.fpReg1))
|
callStack.push(CallSiteContext(pcChunk, pcIndex+1, i.reg1, i.fpReg1))
|
||||||
branchTo(i)
|
branchTo(i)
|
||||||
|
@ -7,10 +7,12 @@ import prog8.intermediate.*
|
|||||||
|
|
||||||
class VmProgramLoader {
|
class VmProgramLoader {
|
||||||
private val placeholders = mutableMapOf<Pair<IRCodeChunk, Int>, String>() // program chunk+index to symbolname
|
private val placeholders = mutableMapOf<Pair<IRCodeChunk, Int>, String>() // program chunk+index to symbolname
|
||||||
|
private val subroutines = mutableMapOf<String, IRSubroutine>() // label to subroutine node
|
||||||
|
|
||||||
fun load(irProgram: IRProgram, memory: Memory): List<IRCodeChunk> {
|
fun load(irProgram: IRProgram, memory: Memory): List<IRCodeChunk> {
|
||||||
placeholders.clear()
|
|
||||||
irProgram.validate()
|
irProgram.validate()
|
||||||
|
placeholders.clear()
|
||||||
|
subroutines.clear()
|
||||||
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
|
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
|
||||||
val variableAddresses = allocations.allocations.toMutableMap()
|
val variableAddresses = allocations.allocations.toMutableMap()
|
||||||
val programChunks = mutableListOf<IRCodeChunk>()
|
val programChunks = mutableListOf<IRCodeChunk>()
|
||||||
@ -48,6 +50,7 @@ class VmProgramLoader {
|
|||||||
}
|
}
|
||||||
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO
|
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO
|
||||||
is IRSubroutine -> {
|
is IRSubroutine -> {
|
||||||
|
subroutines[child.label] = child
|
||||||
child.chunks.forEach { chunk ->
|
child.chunks.forEach { chunk ->
|
||||||
when (chunk) {
|
when (chunk) {
|
||||||
is IRInlineAsmChunk -> {
|
is IRInlineAsmChunk -> {
|
||||||
@ -58,13 +61,14 @@ class VmProgramLoader {
|
|||||||
is IRCodeChunk -> programChunks += chunk
|
is IRCodeChunk -> programChunks += chunk
|
||||||
else -> throw AssemblyError("weird chunk type")
|
else -> throw AssemblyError("weird chunk type")
|
||||||
}
|
}
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pass2translateSyscalls(programChunks)
|
pass2translateSyscalls(programChunks)
|
||||||
pass2replaceLabelsByProgIndex(programChunks, variableAddresses)
|
pass2replaceLabelsByProgIndex(programChunks, variableAddresses, subroutines)
|
||||||
phase2relinkReplacedChunks(chunkReplacements, programChunks)
|
phase2relinkReplacedChunks(chunkReplacements, programChunks)
|
||||||
|
|
||||||
programChunks.forEach {
|
programChunks.forEach {
|
||||||
@ -137,7 +141,8 @@ class VmProgramLoader {
|
|||||||
|
|
||||||
private fun pass2replaceLabelsByProgIndex(
|
private fun pass2replaceLabelsByProgIndex(
|
||||||
chunks: MutableList<IRCodeChunk>,
|
chunks: MutableList<IRCodeChunk>,
|
||||||
variableAddresses: MutableMap<String, Int>
|
variableAddresses: MutableMap<String, Int>,
|
||||||
|
subroutines: MutableMap<String, IRSubroutine>
|
||||||
) {
|
) {
|
||||||
for((ref, label) in placeholders) {
|
for((ref, label) in placeholders) {
|
||||||
val (chunk, line) = ref
|
val (chunk, line) = ref
|
||||||
@ -168,6 +173,33 @@ class VmProgramLoader {
|
|||||||
chunk.instructions[line] = chunk.instructions[line].copy(address = replacement)
|
chunk.instructions[line] = chunk.instructions[line].copy(address = replacement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunks.forEach {
|
||||||
|
it.instructions.withIndex().forEach { (index, ins) ->
|
||||||
|
if(ins.opcode==Opcode.SETPARAM && ins.address==null) {
|
||||||
|
val call = findCall(it, index)
|
||||||
|
if(call.opcode==Opcode.SYSCALL) {
|
||||||
|
// there is no variable to set, SYSCALLs get their args from the stack.
|
||||||
|
} else if(call.labelSymbol!=null) {
|
||||||
|
// set the address in the instruction to the subroutine's parameter variable's address
|
||||||
|
// this avoids having to look it up every time the SETPARAM instruction is encountered during execution
|
||||||
|
val target = subroutines.getValue(call.labelSymbol!!)
|
||||||
|
val paramVar = target.parameters[ins.immediate!!]
|
||||||
|
val address = variableAddresses.getValue(paramVar.name)
|
||||||
|
it.instructions[index] = ins.copy(address = address)
|
||||||
|
} else
|
||||||
|
throw IRParseException("weird call $call")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val functionCallOpcodes = setOf(Opcode.CALL, Opcode.CALLR, Opcode.SYSCALL, Opcode.JUMP, Opcode.JUMPA)
|
||||||
|
private fun findCall(it: IRCodeChunk, startIndex: Int): IRInstruction {
|
||||||
|
var idx = startIndex
|
||||||
|
while(it.instructions[idx].opcode !in functionCallOpcodes)
|
||||||
|
idx++
|
||||||
|
return it.instructions[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun varsToMemory(
|
private fun varsToMemory(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user