add a split-array version for word containment check

This commit is contained in:
Irmen de Jong
2024-12-15 13:35:22 +01:00
parent 8f799567cf
commit 28c721fa7d
6 changed files with 43 additions and 86 deletions

View File

@@ -1941,12 +1941,15 @@ $endLabel""")
} }
dt.isWordArray -> { dt.isWordArray -> {
assignExpressionToVariable(containment.needle, "P8ZP_SCRATCH_W1", elementDt) assignExpressionToVariable(containment.needle, "P8ZP_SCRATCH_W1", elementDt)
if(dt.isSplitWordArray) {
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName+"_lsb", null, null)
asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_splitwordarray")
} else {
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null)
asmgen.out(" ldy #$numElements") asmgen.out(" ldy #$numElements")
if(dt.isSplitWordArray) asmgen.out(" jsr prog8_lib.containment_linearwordarray")
asmgen.out(" jsr prog8_lib.containment_splitwordarray") }
else
asmgen.out(" jsr prog8_lib.containment_wordarray")
} }
else -> throw AssemblyError("invalid dt") else -> throw AssemblyError("invalid dt")
} }

View File

@@ -317,7 +317,7 @@ containment_bytearray .proc
rts rts
.pend .pend
containment_wordarray .proc containment_linearwordarray .proc
; -- check if a value exists in a linear word array. ; -- check if a value exists in a linear word array.
; parameters: P8ZP_SCRATCH_W1: value to check, P8ZP_SCRATCH_W2: address of the word array, Y = number of elements in the array (>=1). ; parameters: P8ZP_SCRATCH_W1: value to check, P8ZP_SCRATCH_W2: address of the word array, Y = number of elements in the array (>=1).
; returns boolean 0/1 in A. ; returns boolean 0/1 in A.
@@ -348,22 +348,31 @@ containment_splitwordarray .proc
; parameters: P8ZP_SCRATCH_W1: value to check, P8ZP_SCRATCH_W2: start address of the lsb word array, Y = number of elements in the array (>=1). ; parameters: P8ZP_SCRATCH_W1: value to check, P8ZP_SCRATCH_W2: start address of the lsb word array, Y = number of elements in the array (>=1).
; returns boolean 0/1 in A. ; returns boolean 0/1 in A.
; TODO FIX THIS! ; store the needle value in SCRATCH_B1(lsb) and SCRATCH_REG(msb)
dey lda P8ZP_SCRATCH_W1
tya sta P8ZP_SCRATCH_B1
asl a
tay
- lda P8ZP_SCRATCH_W1
cmp (P8ZP_SCRATCH_W2),y
bne +
lda P8ZP_SCRATCH_W1+1 lda P8ZP_SCRATCH_W1+1
iny sta P8ZP_SCRATCH_REG
; calculate where the msb array starts and put this in P8ZP_SCRATCH_W1 (_W2 is the start of the lsb array)
tya
clc
adc P8ZP_SCRATCH_W2
sta P8ZP_SCRATCH_W1
lda P8ZP_SCRATCH_W2+1
adc #0
sta P8ZP_SCRATCH_W1+1
; search needle
dey
- lda P8ZP_SCRATCH_REG
cmp (P8ZP_SCRATCH_W1),y
bne +
lda P8ZP_SCRATCH_B1
cmp (P8ZP_SCRATCH_W2),y cmp (P8ZP_SCRATCH_W2),y
beq _found beq _found
dey
+ dey + dey
dey cpy #255
cpy #254
bne - bne -
lda #0 lda #0
rts rts

View File

@@ -83,10 +83,7 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro
val decl = elt.targetVarDecl(program) val decl = elt.targetVarDecl(program)
if(decl!=null && decl.datatype.isSplitWordArray) { if(decl!=null && decl.datatype.isSplitWordArray) {
// you can't take the adress of a split-word array. // you can't take the adress of a split-word array.
// instead of a fatal error, we give a warning and turn it back into a regular array. errors.err("cannot take address of split word array", decl.position)
errors.warn("cannot take address of split word array - the array is turned back into a regular word array", decl.position)
val normalArray = makeNormalArrayFromSplit(decl)
mods.add(IAstModification.ReplaceNode(decl, normalArray, decl.parent))
} }
} }
return mods return mods
@@ -160,22 +157,9 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro
if (variable!=null) { if (variable!=null) {
if (variable.datatype.isSplitWordArray) { if (variable.datatype.isSplitWordArray) {
// you can't take the adress of a split-word array. // you can't take the adress of a split-word array.
// instead of giving a fatal error, we remove the errors.err("cannot take address of split word array", addressOf.position)
// instead of a fatal error, we give a warning and turn it back into a regular array.
errors.warn("cannot take address of split word array - the array is turned back into a regular word array", addressOf.position)
val normalArray = makeNormalArrayFromSplit(variable)
return listOf(IAstModification.ReplaceNode(variable, normalArray, variable.parent))
} }
} }
return noModifications return noModifications
} }
private fun makeNormalArrayFromSplit(variable: VarDecl): VarDecl {
val normalDt = DataType.arrayFor(variable.datatype.sub!!.dt, false)
return VarDecl(
variable.type, variable.origin, normalDt, variable.zeropage, variable.arraysize, variable.name, emptyList(),
variable.value?.copy(), variable.sharedWithAsm, variable.alignment, variable.dirty, variable.position
)
}
} }

View File

@@ -95,43 +95,6 @@ main {
compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null
} }
test("split only for word arrays") {
val srcGood = """
main {
uword[10] @nosplit sw
word[10] @nosplit sw2
sub start() {
}
}"""
compileText(C64Target(), false, srcGood, writeAssembly = false) shouldNotBe null
val srcWrong1 = """
main {
ubyte[10] @nosplit sb
sub start() {
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, srcWrong1, writeAssembly = false, errors=errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "nosplit can only be used on word arrays"
val srcWrong2 = """
%option enable_floats
main {
float[10] @nosplit sf
sub start() {
}
}"""
errors.clear()
compileText(C64Target(), false, srcWrong2, writeAssembly = false, errors=errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "nosplit can only be used on word arrays"
}
test("split word arrays in asm as lsb/msb, nosplit as single linear") { test("split word arrays in asm as lsb/msb, nosplit as single linear") {
val text = """ val text = """
main { main {

View File

@@ -3,9 +3,8 @@ TODO
- DONE: make word arrays split by default (remove @split tag) and use new @nosplit tag to make an array use the old storage format? Also invert -splitarrays command line option. - DONE: make word arrays split by default (remove @split tag) and use new @nosplit tag to make an array use the old storage format? Also invert -splitarrays command line option.
- DONE: remove "splitarrays" %option switch - DONE: remove "splitarrays" %option switch
- Regular & will just return the start of the split array in memory whatever byte comes first. - Regular & will just return the start of the split array in memory whatever byte comes first. Search "cannot take address of split word array"
- add &< and &> operators to get the address of the lsb-array and msb-array, respectively. - add &< and &> operators to get the address of the lsb-array and msb-array, respectively.
- fix containment_splitwordarray
- fix sprites.pos_batch - fix sprites.pos_batch
- fix anyall.anyw/allw - fix anyall.anyw/allw
- update Syntax files + Document all of this (also that word arrays can then have length 256 by default as well, and that @linear will reduce it to half.) - update Syntax files + Document all of this (also that word arrays can then have length 256 by default as well, and that @linear will reduce it to half.)

View File

@@ -2,14 +2,13 @@
%zeropage basicsafe %zeropage basicsafe
main { main {
uword[] array = [1000, 2000, 9000, 8000, 5000]
sub start() { sub start() {
txt.print_bool(1000 in array) uword[] addresses = [scores2, start]
txt.spc() uword[] scores1 = [10, 25, 50, 100]
txt.print_bool(9000 in array) uword[] scores2 = [100, 250, 500, 1000]
txt.spc()
txt.print_bool(5000 in array) cx16.r0 = &scores1
txt.spc() cx16.r1 = &scores2
txt.print_bool(9001 in array) cx16.r2 = &addresses
} }
} }