mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
vm: replaced prog8_lib.string_compare and others with syscalls
This commit is contained in:
parent
0f1a4b9d8f
commit
469e042216
@ -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)
|
||||
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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}")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user