support word size indexing on typed pointers

This commit is contained in:
Irmen de Jong
2025-08-25 22:18:47 +02:00
parent 3cdb25ce8e
commit 0f79351de9
9 changed files with 199 additions and 291 deletions

View File

@@ -1594,8 +1594,15 @@ internal class AstChecker(private val program: Program,
}
else {
if (leftDt.isBool || rightDt.isBool) {
if(expr.operator!="==" && expr.operator!="!=")
errors.err("operator requires numeric operands", expr.right.position)
if(expr.operator!="==" && expr.operator!="!=") {
val msg = when(expr.operator) {
"^" -> "operator requires numeric operands, did you mean logical 'xor'?"
"&" -> "operator requires numeric operands, did you mean logical 'and'?"
"|" -> "operator requires numeric operands, did you mean logical 'or'?"
else -> "operator requires numeric operands"
}
errors.err(msg, expr.right.position)
}
}
}
}

View File

@@ -240,6 +240,7 @@ _after:
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
// replace pointervar[word] by @(pointervar+word) to avoid the
// "array indexing is limited to byte size 0..255" error for pointervariables.
// (uses pokew or pokef if the ointer is a word or float pointer).
if(arrayIndexedExpression.pointerderef!=null) {
return noModifications
@@ -247,7 +248,7 @@ _after:
val indexExpr = arrayIndexedExpression.indexer.indexExpr
val arrayVar = arrayIndexedExpression.plainarrayvar!!.targetVarDecl()
if(arrayVar!=null && (arrayVar.datatype.isUnsignedWord || (arrayVar.datatype.isPointer && arrayVar.datatype.sub==BaseDataType.UBYTE))) {
if(arrayVar!=null && (arrayVar.datatype.isUnsignedWord || arrayVar.datatype.isPointer)) {
val wordIndex = TypecastExpression(indexExpr, DataType.UWORD, true, indexExpr.position)
val address = BinaryExpression(
arrayIndexedExpression.plainarrayvar!!.copy(),
@@ -255,22 +256,58 @@ _after:
wordIndex,
arrayIndexedExpression.position
)
return if (parent is AssignTarget) {
// assignment to array
val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position)
val newtarget = AssignTarget(
null,
null,
memwrite,
null,
false,
position = arrayIndexedExpression.position
)
listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent))
} else {
// read from array
val memread = DirectMemoryRead(address, arrayIndexedExpression.position)
listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent))
if(arrayVar.datatype.isUnsignedWord || arrayVar.datatype.sub?.isByte==true) {
return if (parent is AssignTarget) {
// assignment to array
val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position)
val newtarget = AssignTarget(null, null, memwrite, null, false, position = arrayIndexedExpression.position)
listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent))
} else {
// read from array
val memread = DirectMemoryRead(address, arrayIndexedExpression.position)
val replacement = if(arrayVar.datatype.sub?.isSigned==true)
TypecastExpression(memread, DataType.BYTE, true, memread.position)
else
memread
listOf(IAstModification.ReplaceNode(arrayIndexedExpression, replacement, parent))
}
} else if(arrayVar.datatype.sub?.isWord==true) {
// use peekw/pokew
if(parent is AssignTarget) {
val assignment = parent.parent as Assignment
val args = mutableListOf(address, assignment.value)
val poke = FunctionCallStatement(IdentifierReference(listOf("pokew"), arrayIndexedExpression.position), args, false, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(assignment, poke, assignment.parent))
} else {
val peek = FunctionCallExpression(IdentifierReference(listOf("peekw"), arrayIndexedExpression.position), mutableListOf(address), arrayIndexedExpression.position)
val replacement = if(arrayVar.datatype.sub?.isSigned==true)
TypecastExpression(peek, DataType.WORD, true, peek.position)
else
peek
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, replacement, parent))
}
} else if(arrayVar.datatype.sub==BaseDataType.BOOL) {
// use peekbool/pokebool
if(parent is AssignTarget) {
val assignment = parent.parent as Assignment
val args = mutableListOf(address, assignment.value)
val poke = FunctionCallStatement(IdentifierReference(listOf("pokebool"), arrayIndexedExpression.position), args, false, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(assignment, poke, assignment.parent))
} else {
val peek = FunctionCallExpression(IdentifierReference(listOf("peekbool"), arrayIndexedExpression.position), mutableListOf(address), arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, peek, parent))
}
} else if(arrayVar.datatype.sub==BaseDataType.FLOAT) {
// use peekf/pokef
if(parent is AssignTarget) {
val assignment = parent.parent as Assignment
val args = mutableListOf(address, assignment.value)
val poke = FunctionCallStatement(IdentifierReference(listOf("pokef"), arrayIndexedExpression.position), args, false, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(assignment, poke, assignment.parent))
} else {
val peek = FunctionCallExpression(IdentifierReference(listOf("peekf"), arrayIndexedExpression.position), mutableListOf(address), arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, peek, parent))
}
}
} else if(arrayVar!=null && (arrayVar.type==VarDeclType.MEMORY || arrayVar.datatype.isString || arrayVar.datatype.isPointer || arrayVar.datatype.isArray)) {
return noModifications

View File

@@ -840,7 +840,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
// don't multiply simply shift
offset = PtBinaryExpression("<<", DataType.UWORD, expr.position)
offset.add(transformExpression(expr.right))
offset.add(PtNumber(BaseDataType.UWORD, log2(structSize.toDouble()), expr.position))
offset.add(PtNumber(BaseDataType.UBYTE, log2(structSize.toDouble()), expr.position))
}
else {
offset = PtBinaryExpression("*", DataType.UWORD, expr.position)

View File

@@ -332,11 +332,11 @@ main {
st.size shouldBe 27
val a_zz = (st[20] as Assignment).value
a_zz shouldBe instanceOf<ArrayIndexedExpression>()
a_zz shouldBe instanceOf<FunctionCallExpression>()
val a_fl = (st[21] as Assignment).value
a_fl shouldBe instanceOf<ArrayIndexedExpression>()
a_fl shouldBe instanceOf<FunctionCallExpression>()
val a_bb = (st[22] as Assignment).value
a_bb shouldBe instanceOf<ArrayIndexedExpression>()
a_bb shouldBe instanceOf<DirectMemoryRead>()
val a_r0 = (st[23] as Assignment).value
a_r0 shouldBe instanceOf<DirectMemoryRead>()
val a_r1 = (st[24] as Assignment).value
@@ -885,28 +885,6 @@ main {
compileText(Cx16Target(), false, src, outputDir) shouldNotBe null
}
test("uword as pointer versus pointer to uword difference") {
val src="""
main {
sub start() {
uword @shared ptr1
^^uword @shared ptr2
ptr1[2] = 1
ptr2[2] = 1
}
}"""
compileText(C64Target(), false, src, outputDir) shouldNotBe null
val result = compileText(VMTarget(), false, src, outputDir)!!
val st = result.codegenAst!!.entrypoint()!!.children
st.size shouldBe 8
val a1 = st[5] as PtAssignment
val a2 = st[6] as PtAssignment
a1.target.memory shouldNotBe null
a2.target.array shouldNotBe null
}
test("array indexing on non pointer fields give correct error messages") {
val src="""
main {
@@ -1021,15 +999,15 @@ main {
val dr7 = (st[17] as Assignment).target.pointerDereference!!
val dr8 = (st[18] as Assignment).target.pointerDereference!!
val dr9 = (st[19] as Assignment).value as PtrDereference
val dr9 = (st[19] as Assignment).value as FunctionCallExpression
val dr10 = (st[20] as Assignment).value as PtrDereference
val dr11 = (st[21] as Assignment).target.pointerDereference!!
val dr12 = (st[22] as Assignment).target.pointerDereference!!
(st[22] as FunctionCallStatement).target.nameInSource shouldBe listOf("pokew")
val dr13 = (st[23] as Assignment).value as PtrDereference
val dr14 = (st[24] as Assignment).value as PtrDereference
((st[24] as Assignment).value as FunctionCallExpression).target.nameInSource shouldBe listOf("peekf")
val dr15 = (st[25] as Assignment).target.pointerDereference!!
val dr16 = (st[26] as Assignment).target.pointerDereference!!
(st[26] as FunctionCallStatement).target.nameInSource shouldBe listOf("pokef")
dr0.chain shouldBe listOf("l1", "s")
dr0.derefLast shouldBe true
@@ -1051,23 +1029,16 @@ main {
dr8.chain shouldBe listOf("l1", "s")
dr8.derefLast shouldBe true
dr9.chain shouldBe listOf("wptr")
dr9.derefLast shouldBe true
dr9.target.nameInSource shouldBe listOf("peekw")
dr10.chain shouldBe listOf("wptr")
dr10.derefLast shouldBe true
dr11.chain shouldBe listOf("wptr")
dr11.derefLast shouldBe true
dr12.chain shouldBe listOf("wptr")
dr12.derefLast shouldBe true
dr13.chain shouldBe listOf("fptr")
dr13.derefLast shouldBe true
dr14.chain shouldBe listOf("fptr")
dr14.derefLast shouldBe true
dr15.chain shouldBe listOf("fptr")
dr15.derefLast shouldBe true
dr16.chain shouldBe listOf("fptr")
dr16.derefLast shouldBe true
}
test("global and local pointer vars") {
@@ -1721,6 +1692,84 @@ main {
compileText(Cx16Target(), false, src, outputDir) shouldNotBe null
}
test("array indexing on a pointer with a word size index works") {
val src="""
%import floats
main {
sub start() {
^^ubyte @shared ptr1 = $4000
^^uword @shared ptr2 = $4000
^^float @shared ptr3 = $4000
^^bool @shared ptr4 = $4000
uword @shared untyped = $4000
float @shared fl
bool @shared bb, bb2
untyped[$1000] = 0
ptr1[$1000] = 0
ptr2[$1000] = 0
ptr3[$1000] = 0
ptr4[$1000] = false
untyped[$1000] = 99
ptr1[$1000] = 99
ptr2[$1000] = 99
ptr3[$1000] = 99
ptr4[$1000] = true
untyped[$1000] = cx16.r0L
ptr1[$1000] = cx16.r0L
ptr2[$1000] = cx16.r0L
ptr3[$1000] = fl
ptr4[$1000] = bb
untyped[$1000] = cx16.r0L+1
ptr1[$1000] = cx16.r0L+1
ptr2[$1000] = cx16.r0L+1
ptr3[$1000] = fl+1.1
ptr4[$1000] = bb xor bb2
untyped[$1000 + cx16.r0] = 0
ptr1[$1000 + cx16.r0] = 0
ptr2[$1000 + cx16.r0] = 0
ptr3[$1000 + cx16.r0] = 0
ptr4[$1000 + cx16.r0] = false
untyped[$1000 + cx16.r0] = 99
ptr1[$1000 + cx16.r0] = 99
ptr2[$1000 + cx16.r0] = 99
ptr3[$1000 + cx16.r0] = 99
ptr4[$1000 + cx16.r0] = true
untyped[$1000 + cx16.r0] = cx16.r0L
ptr1[$1000 + cx16.r0] = cx16.r0L
ptr2[$1000 + cx16.r0] = cx16.r0L
ptr3[$1000 + cx16.r0] = fl
ptr4[$1000 + cx16.r0] = bb
untyped[$1000 + cx16.r0] = cx16.r0L+1
ptr1[$1000 + cx16.r0] = cx16.r0L+1
ptr2[$1000 + cx16.r0] = cx16.r0L+1
ptr3[$1000 + cx16.r0] = fl+1.1
ptr4[$1000 + cx16.r0] = bb xor bb2
cx16.r0L = untyped[$1000]
cx16.r1L = ptr1[$1000]
cx16.r2 = ptr2[$1000]
fl = ptr3[$1000]
bb = ptr4[$1000]
cx16.r0L = untyped[cx16.r0]
cx16.r1L = ptr1[cx16.r0]
cx16.r2 = ptr2[cx16.r0]
fl = ptr3[cx16.r0]
bb = ptr4[cx16.r0]
cx16.r0L = untyped[cx16.r0+1]
cx16.r1L = ptr1[cx16.r0+1]
cx16.r2 = ptr2[cx16.r0+1]
fl = ptr3[cx16.r0+1]
bb = ptr4[cx16.r0+1]
}
}"""
compileText(VMTarget(), false, src, outputDir) shouldNotBe null
compileText(C64Target(), false, src, outputDir) shouldNotBe null
}
test("correct type of address of split and nosplit arrays") {
val src="""
main {