vm: replaced prog8_lib.string_compare and others with syscalls

This commit is contained in:
Irmen de Jong 2022-11-04 22:37:42 +01:00
parent 0f1a4b9d8f
commit 469e042216
8 changed files with 143 additions and 92 deletions

View File

@ -101,24 +101,49 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
when(iterable.dt) {
DataType.STR -> {
val call = PtFunctionCall(listOf("prog8_lib", "string_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element)
call.children.add(check.iterable)
result += translate(call, resultRegister, resultFpRegister)
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
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {
val call = PtFunctionCall(listOf("prog8_lib", "bytearray_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element)
call.children.add(check.iterable)
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
result += translate(call, resultRegister, resultFpRegister)
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
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
val call = PtFunctionCall(listOf("prog8_lib", "wordarray_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element)
call.children.add(check.iterable)
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
result += translate(call, resultRegister, resultFpRegister)
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
}
DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported")
else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}")
@ -307,17 +332,23 @@ 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) {
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
comparisonCall.children.add(binExpr.left)
comparisonCall.children.add(binExpr.right)
result += translate(comparisonCall, resultRegister, -1)
val zeroRegister = codeGen.registers.nextFree()
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0), null)
val instr = if(greaterEquals)
IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
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=zeroRegister)
addInstr(result, instr, null)
IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1=resultRegister, reg2=1)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
result += syscall
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)
@ -357,17 +388,23 @@ 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) {
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
comparisonCall.children.add(binExpr.left)
comparisonCall.children.add(binExpr.right)
result += translate(comparisonCall, resultRegister, -1)
val zeroRegister = codeGen.registers.nextFree()
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0), null)
val ins = if(lessEquals)
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
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=zeroRegister)
addInstr(result, ins, null)
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1=resultRegister, reg2=1)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
result += syscall
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)
@ -403,13 +440,21 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
comparisonCall.children.add(binExpr.left)
comparisonCall.children.add(binExpr.right)
result += translate(comparisonCall, resultRegister, -1)
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)
addInstr(result, IRInstruction(Opcode.INV, vmDt, reg1=resultRegister), null)
addInstr(result, IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1), null)
syscall += IRInstruction(Opcode.INV, vmDt, reg1=resultRegister)
syscall += IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
result += syscall
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)

View File

@ -3,49 +3,4 @@
prog8_lib {
%option force_output
sub string_contains(ubyte needle, str haystack) -> ubyte {
repeat {
if @(haystack)==0
return false
if @(haystack)==needle
return true
haystack++
}
}
sub bytearray_contains(ubyte needle, uword haystack_ptr, ubyte num_elements) -> ubyte {
haystack_ptr--
while num_elements {
if haystack_ptr[num_elements]==needle
return true
num_elements--
}
return false
}
sub wordarray_contains(uword needle, uword haystack_ptr, ubyte num_elements) -> ubyte {
haystack_ptr += (num_elements-1) * 2
while num_elements {
if peekw(haystack_ptr)==needle
return true
haystack_ptr -= 2
num_elements--
}
return false
}
sub string_compare(str st1, str st2) -> byte {
; Compares two strings for sorting.
; Returns -1 (255), 0 or 1 depending on wether string1 sorts before, equal or after string2.
; Note that you can also directly compare strings and string values with eachother using
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
%ir {{
loadm.w r0,prog8_lib.string_compare.st1
loadm.w r1,prog8_lib.string_compare.st2
syscall 29
return
}}
}
}

View File

@ -83,7 +83,12 @@ string {
; Returns -1 (255), 0 or 1 depending on wether string1 sorts before, equal or after string2.
; Note that you can also directly compare strings and string values with eachother using
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
return prog8_lib.string_compare(st1, st2)
%ir {{
loadm.w r0,string.compare.st1
loadm.w r1,string.compare.st2
syscall 29
return
}}
}
sub lower(str st) -> ubyte {

View File

@ -3,8 +3,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- fix expericodegen crashes from missing functions from virtual/prog8_lib.p8
...
@ -19,6 +17,7 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- ir/vm: SYSCALL opcode should take args in r65500, r65501 etc instead of r0, r1. Then also remove excess PUSH/POP of regs to save them.
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)

View File

@ -15,10 +15,11 @@ main {
uword value2 = 3333
txt.print_ub(value in name1)
txt.print_ub('c' in name1)
txt.print_ub(name1 == name2)
txt.print_ub(name1 < name2)
txt.print_ub(value in arr1)
txt.print_ub(value2 in arr2)
txt.print_ub(name1 == name2)
txt.print_ub(name1 < name2)
txt.print_ub(name1 >= name2)
}
}

View File

@ -17,5 +17,9 @@ enum class IMSyscall(val number: Int) {
ALL_FLOAT(10009),
REVERSE_BYTES(10010),
REVERSE_WORDS(10011),
REVERSE_FLOATS(10012)
REVERSE_FLOATS(10012),
COMPARE_STRINGS(10013),
STRING_CONTAINS(10014),
BYTEARRAY_CONTAINS(10015),
WORDARRAY_CONTAINS(10016)
}

View File

@ -77,7 +77,10 @@ enum class Syscall {
RNDFSEED,
RND,
RNDW,
RNDF
RNDF,
STRING_CONTAINS,
BYTEARRAY_CONTAINS,
WORDARRAY_CONTAINS
}
object SysCalls {
@ -311,6 +314,41 @@ object SysCalls {
Syscall.RNDF -> {
vm.registers.setFloat(0, vm.randomGeneratorFloats.nextFloat())
}
Syscall.STRING_CONTAINS -> {
val char = vm.registers.getUB(0).toInt().toChar()
val stringAddr = vm.registers.getUW(1)
val string = vm.memory.getString(stringAddr.toInt())
vm.registers.setUB(0, if(char in string) 1u else 0u)
}
Syscall.BYTEARRAY_CONTAINS -> {
val value = vm.registers.getUB(0)
var array = vm.registers.getUW(1).toInt()
var length = vm.registers.getUB(2)
while(length>0u) {
if(vm.memory.getUB(array)==value) {
vm.registers.setUB(0, 1u)
return
}
array++
length--
}
vm.registers.setUB(0, 0u)
}
Syscall.WORDARRAY_CONTAINS -> {
// r0.w = value, r1.w = array, r2.b = array length
val value = vm.registers.getUW(0)
var array = vm.registers.getUW(1).toInt()
var length = vm.registers.getUB(2)
while(length>0u) {
if(vm.memory.getUW(array)==value) {
vm.registers.setUB(0, 1u)
return
}
array += 2
length--
}
vm.registers.setUB(0, 0u)
}
else -> throw AssemblyError("missing syscall ${call.name}")
}
}

View File

@ -117,6 +117,10 @@ class VmProgramLoader {
IMSyscall.REVERSE_BYTES.number -> Syscall.REVERSE_BYTES
IMSyscall.REVERSE_WORDS.number -> Syscall.REVERSE_WORDS
IMSyscall.REVERSE_FLOATS.number -> Syscall.REVERSE_FLOATS
IMSyscall.COMPARE_STRINGS.number -> Syscall.COMPARE_STRINGS
IMSyscall.STRING_CONTAINS.number -> Syscall.STRING_CONTAINS
IMSyscall.BYTEARRAY_CONTAINS.number -> Syscall.BYTEARRAY_CONTAINS
IMSyscall.WORDARRAY_CONTAINS.number -> Syscall.WORDARRAY_CONTAINS
else -> null
}