added containment check of float arrays

This commit is contained in:
Irmen de Jong 2024-01-14 13:20:12 +01:00
parent 41de8caa13
commit 0a356ba73a
15 changed files with 110 additions and 21 deletions

View File

@ -1940,7 +1940,10 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.out(" jsr prog8_lib.containment_bytearray")
}
DataType.ARRAY_F -> {
TODO("containment check of floats")
assignExpressionToRegister(containment.element, RegisterOrPair.FAC1, true)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null)
asmgen.out(" ldy #$numElements")
asmgen.out(" jsr floats.containment_floatarray")
}
DataType.ARRAY_B, DataType.ARRAY_UB -> {
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)

View File

@ -565,7 +565,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcLsb(call: PtBuiltinFunctionCall): ExpressionCodeResult {
return exprGen.translateExpression(call.args.single())
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
// TODO to be more strict, maybe we *should* introduce a new result register that is of type .b?
// ....To be more strict, maybe we should introduce a new result register that is of type .b?
}
private fun funcMsb(call: PtBuiltinFunctionCall): ExpressionCodeResult {

View File

@ -154,7 +154,19 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
result += codeGen.makeSyscall(IMSyscall.WORDARRAY_CONTAINS, listOf(IRDataType.WORD to elementTr.resultReg, IRDataType.WORD to iterableTr.resultReg, IRDataType.BYTE to lengthReg), IRDataType.BYTE to elementTr.resultReg)
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
}
DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported")
DataType.ARRAY_F -> {
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
val elementTr = translateExpression(check.element)
addToResult(result, elementTr, -1, elementTr.resultFpReg)
val iterableTr = translateExpression(check.iterable)
addToResult(result, iterableTr, iterableTr.resultReg, -1)
val lengthReg = codeGen.registers.nextFree()
val resultReg = codeGen.registers.nextFree()
val iterableLength = codeGen.symbolTable.getLength(check.iterable.name)
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, immediate = iterableLength!!), null)
result += codeGen.makeSyscall(IMSyscall.FLOATARRAY_CONTAINS, listOf(IRDataType.FLOAT to elementTr.resultFpReg, IRDataType.WORD to iterableTr.resultReg, IRDataType.BYTE to lengthReg), IRDataType.BYTE to resultReg)
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
else -> throw AssemblyError("weird iterable dt ${check.iterable.type} for ${check.iterable.name}")
}
}

View File

@ -1709,7 +1709,7 @@ class IRCodeGen(
is PtLabel -> {
irBlock += IRCodeChunk(child.name, null)
}
else -> TODO("weird child node $child")
else -> TODO("weird block child node $child")
}
}
return irBlock

View File

@ -419,7 +419,6 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
// TODO: detect multiple loads to the same target registers, only keep first (if source is not I/O memory)
// TODO: detect multiple stores to the same target, only keep first (if target is not I/O memory)
// TODO: detect multiple float ffrom/fto to the same target, only keep first
// TODO: detect multiple sequential rnd with same reg1, only keep one
// TODO: detect subsequent same xors/nots/negs, remove the pairs completely as they cancel out
// TODO: detect multiple same ands, ors; only keep first
// TODO: (hard) detect multiple registers being assigned the same value (and not changed) - use only 1 of them

View File

@ -221,7 +221,7 @@ class IRUnusedCodeRemover(
}
// make sure that chunks that are only used as a prefix of a label, are also marked as linked
linkedChunks.forEach { chunk ->
linkedChunks.toList().forEach { chunk ->
chunk.instructions.forEach {
if(it.labelSymbol!=null) {
val chunkName = it.labelSymbol!!.substringBeforeLast('.')

View File

@ -147,3 +147,54 @@ func_sqrt_into_FAC1 .proc
jsr MOVFM
jmp SQR
.pend
containment_floatarray .proc
; -- check if a value exists in a float array.
; parameters: FAC1: value to check, P8ZP_SCRATCH_W1: address of the word array, Y = length of array (>=1).
; returns boolean 0/1 in A.
sty P8ZP_SCRATCH_REG
ldx #<floats.floats_temp_var
ldy #>floats.floats_temp_var
jsr floats.MOVMF
ldx P8ZP_SCRATCH_REG
ldy #0
- lda floats.floats_temp_var
cmp (P8ZP_SCRATCH_W1),y
bne _firstmiss
iny
lda floats.floats_temp_var+1
cmp (P8ZP_SCRATCH_W1),y
bne _secondmiss
iny
lda floats.floats_temp_var+2
cmp (P8ZP_SCRATCH_W1),y
bne _thirdmiss
iny
lda floats.floats_temp_var+3
cmp (P8ZP_SCRATCH_W1),y
bne _fourthmiss
iny
lda floats.floats_temp_var+4
cmp (P8ZP_SCRATCH_W1),y
bne _fifthmiss
lda #1
rts
_firstmiss
iny
_secondmiss
iny
_thirdmiss
iny
_fourthmiss
iny
_fifthmiss
iny
dex
bne -
lda #0
rts
.pend

View File

@ -708,7 +708,7 @@ gfx2 {
while cx16.r12L {
pop_stack()
xx = x1
; TODO: if mode==1 (256c) use vera autodecrement instead of pget(), but code bloat not worth it?
; possible speed optimization: if mode==1 (256c) use vera autodecrement instead of pget(), but code bloat not worth it?
while xx >= 0 {
if pget(xx as uword, yy as uword) != cx16.r11L
break
@ -726,7 +726,7 @@ gfx2 {
do {
cx16.r9 = xx
; TODO: if mode==1 (256c) use vera autoincrement instead of pget(), but code bloat not worth it?
; possible speed optimization: if mode==1 (256c) use vera autoincrement instead of pget(), but code bloat not worth it?
while xx <= width-1 {
if pget(xx as uword, yy as uword) != cx16.r11L
break

View File

@ -454,12 +454,12 @@ skip:
; -- select the text charset to use with the text() routine
; the charset number is the same as for the cx16.screen_set_charset() ROM function.
; 1 = ISO charset, 2 = PETSCII uppercase+graphs, 3= PETSCII uppercase+lowercase.
; TODO vm has no bitmap charset
; TODO vm bitmap charset
}
sub text(uword @zp xx, uword yy, bool draw, uword sctextptr) {
; -- Write some text at the given pixel position. The text string must be in screencode encoding (not petscii!).
; You must also have called text_charset() first to select and prepare the character set to use.
; TODO vm has no bitmap charset
; TODO vm bitmap charset
}
}

View File

@ -1,6 +1,10 @@
TODO
====
split words sort and reverse
split words rol and ror and rol2/ror2
split words any and all
Mark had a compiler crash FatalAstException: invalid dt
...
@ -33,6 +37,7 @@ Compiler:
- ir: idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
global initialization values are simply a list of LOAD instructions.
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.
- ir: fix call() return value handling
- ir: add more optimizations in IRPeepholeOptimizer
- ir: the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line.
maybe another representation is needed once actual codegeneration is done from the IR...?
@ -59,7 +64,7 @@ Optimizations:
for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code,
those checks should probably be removed, or be made permanent
- optimizeCommonSubExpressions: currently only looks in expressions on a single line, could search across multiple expressions
STRUCTS again?
--------------

View File

@ -1,12 +1,13 @@
%import textio
%import sprites
%import floats
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
float[] fa = [1.1, 2.2, 3.3]
float @shared fl = 2.2
cx16.mouse_config2(1)
sprites.set_mousepointer_hand()
txt.print_ub(fl in fa)
}
}

View File

@ -22,10 +22,11 @@ enum class IMSyscall(val number: Int) {
STRING_CONTAINS(0x100e),
BYTEARRAY_CONTAINS(0x100f),
WORDARRAY_CONTAINS(0x1010),
CLAMP_UBYTE(0x1011),
CLAMP_BYTE(0x1012),
CLAMP_UWORD(0x1013),
CLAMP_WORD(0x1014),
CLAMP_FLOAT(0x1015),
CALLFAR(0x1016),
FLOATARRAY_CONTAINS(0x1011),
CLAMP_UBYTE(0x1012),
CLAMP_BYTE(0x1013),
CLAMP_UWORD(0x1014),
CLAMP_WORD(0x1015),
CLAMP_FLOAT(0x1016),
CALLFAR(0x1017),
}

View File

@ -55,6 +55,7 @@ SYSCALLS:
45 = str to float
46 = MUL16_LAST_UPPER
47 = float to str
48 = FLOATARRAY_CONTAINS
*/
enum class Syscall {
@ -105,7 +106,8 @@ enum class Syscall {
ATAN,
STR_TO_FLOAT,
MUL16_LAST_UPPER,
FLOAT_TO_STR
FLOAT_TO_STR,
FLOATARRAY_CONTAINS,
;
companion object {
@ -456,6 +458,18 @@ object SysCalls {
}
returnValue(callspec.returns!!, 0u, vm)
}
Syscall.FLOATARRAY_CONTAINS -> {
val (value, arrayV, lengthV) = getArgValues(callspec.arguments, vm)
var length = lengthV as UByte
var array = (arrayV as UShort).toInt()
while(length>0u) {
if(vm.memory.getFloat(array)==value)
return returnValue(callspec.returns!!, 1u, vm)
array += vm.machinedef.FLOAT_MEM_SIZE
length--
}
returnValue(callspec.returns!!, 0u, vm)
}
Syscall.CLAMP_BYTE -> {
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
val value = (valueU as UByte).toByte().toInt()

View File

@ -2,6 +2,7 @@ package prog8.vm
import prog8.code.core.toHex
import prog8.code.target.virtual.IVirtualMachineRunner
import prog8.code.target.virtual.VirtualMachineDefinition
import prog8.intermediate.*
import java.awt.Color
import java.awt.Toolkit
@ -34,6 +35,7 @@ class BreakpointException(val pcChunk: IRCodeChunk, val pcIndex: Int): Exception
class VirtualMachine(irProgram: IRProgram) {
class CallSiteContext(val returnChunk: IRCodeChunk, val returnIndex: Int, val fcallSpec: FunctionCallArgs)
val memory = Memory()
val machinedef = VirtualMachineDefinition()
val program: List<IRCodeChunk>
val registers = Registers()
val callStack = Stack<CallSiteContext>()

View File

@ -119,6 +119,7 @@ class VmProgramLoader {
IMSyscall.STRING_CONTAINS.number -> Syscall.STRING_CONTAINS
IMSyscall.BYTEARRAY_CONTAINS.number -> Syscall.BYTEARRAY_CONTAINS
IMSyscall.WORDARRAY_CONTAINS.number -> Syscall.WORDARRAY_CONTAINS
IMSyscall.FLOATARRAY_CONTAINS.number -> Syscall.FLOATARRAY_CONTAINS
IMSyscall.CLAMP_BYTE.number -> Syscall.CLAMP_BYTE
IMSyscall.CLAMP_UBYTE.number -> Syscall.CLAMP_UBYTE
IMSyscall.CLAMP_WORD.number -> Syscall.CLAMP_WORD