From abeefb5655b19ec8943903dbe3a2a943a7dc6cfe Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 24 Sep 2025 22:23:26 +0200 Subject: [PATCH] improved pointer[0] --- .../prog8/optimizer/ExpressionSimplifier.kt | 14 +- .../astprocessing/StatementReorderer.kt | 21 +++ compiler/test/TestPointers.kt | 162 ++++++------------ docs/source/todo.rst | 2 +- examples/test.p8 | 8 +- 5 files changed, 90 insertions(+), 117 deletions(-) diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index 28326d36c..dc07acb16 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -492,17 +492,27 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr return noModifications } - override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { if(arrayIndexedExpression.indexer.constIndex()==0) { if(arrayIndexedExpression.plainarrayvar!=null) { - if((arrayIndexedExpression.parent as? BinaryExpression)?.operator !=".") { + val binexprParent = arrayIndexedExpression.parent as? BinaryExpression + if(binexprParent?.operator!=".") { val dt = arrayIndexedExpression.plainarrayvar!!.inferType(program).getOrUndef() if(dt.isPointer) { // pointer[0] --> pointer^^ val deref = PtrDereference(arrayIndexedExpression.plainarrayvar!!.nameInSource, true, arrayIndexedExpression.plainarrayvar!!.position) return listOf(IAstModification.ReplaceNode(arrayIndexedExpression,deref, parent)) } + } else if(arrayIndexedExpression.pointerderef==null) { + // possibly pointer[0].field --> pointer.field + val target = arrayIndexedExpression.plainarrayvar!!.targetVarDecl() + if(target?.datatype?.isPointer==true) { + val field = (binexprParent.right as? IdentifierReference)?.nameInSource + if(field!=null) { + val deref = PtrDereference(arrayIndexedExpression.plainarrayvar!!.nameInSource + field, false, arrayIndexedExpression.plainarrayvar!!.position) + return listOf(IAstModification.ReplaceNode(arrayIndexedExpression.parent, deref, arrayIndexedExpression.parent.parent)) + } + } } } val ptrDeref = arrayIndexedExpression.pointerderef diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index a94217c53..fd24d85f7 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -384,4 +384,25 @@ internal class StatementReorderer( ) return listOf(IAstModification.ReplaceNode(assign, strcopy, assign.parent)) } + + override fun after(deref: ArrayIndexedPtrDereference, parent: Node): Iterable { + if(parent is AssignTarget) { + val zeroIndexer = deref.chain.firstOrNull { it.second?.constIndex()==0 } + if(zeroIndexer!=null) { + val target = deref.definingScope.lookup(listOf(zeroIndexer.first)) + if(target is VarDecl && target.datatype.isPointer) { + val position = deref.chain.indexOf(zeroIndexer) + val rest = deref.chain.drop(position + 1) + if (rest.size == 1 && rest[0].second == null) { + // pointer[0]^^.field = xxx --> pointer^^.field = xxx + val noindexer = zeroIndexer.first to null + val newchain = deref.chain.take(position) + noindexer + rest + val newDeref = PtrDereference(newchain.map { it.first }, false, deref.position) + return listOf(IAstModification.ReplaceNode(deref, newDeref, parent)) + } + } + } + } + return noModifications + } } diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index a9f9b37f9..1b14db8df 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -1027,118 +1027,6 @@ main { st[8] shouldBe instanceOf() } - test("indexing pointers with index 0 is just a direct pointer dereference except when followed by a struct field lookup") { - val src=""" -%import floats -main { - struct List { - ^^uword s - ubyte n - } - sub start() { - ^^List l1 = ^^List : [] - ^^word @shared wptr - ^^float @shared fptr - float f1,f2 - - cx16.r0 = l1.s^^ - cx16.r1 = l1^^.s^^ - cx16.r2 = l1.s^^ - cx16.r3 = l1.s[0] - cx16.r4 = l1^^.s[0] - - l1.s^^ = 4242 - l1^^.s^^ = 4242 - l1.s^^ = 4242 - l1.s[0] = 4242 - ;; l1^^.s[0] = 4242 ; TODO fix parse syntax error - - cx16.r0s = wptr[0] - cx16.r1s = wptr^^ - wptr^^ = 4242 - wptr[0] = 4242 - - f1 = fptr^^ - f2 = fptr[0] - fptr^^ = 1.234 - fptr[0] = 1.234 - - ; not changed to dereference: - cx16.r0L = l1[0].n - cx16.r1L = l1[1].n - } -}""" - - val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = false)!! - val st = result.compilerAst.entrypoint.statements - st.size shouldBe 30 - val dr0 = (st[10] as Assignment).value as PtrDereference - val dr1 = (st[11] as Assignment).value as PtrDereference - val dr2 = (st[12] as Assignment).value as PtrDereference - val dr3 = (st[13] as Assignment).value as PtrDereference - val dr4 = (st[14] as Assignment).value as PtrDereference - - val dr5 = (st[15] as Assignment).target.pointerDereference!! - val dr6 = (st[16] as Assignment).target.pointerDereference!! - val dr7 = (st[17] as Assignment).target.pointerDereference!! - val dr8 = (st[18] as Assignment).target.pointerDereference!! - - 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!! - (st[22] as FunctionCallStatement).target.nameInSource shouldBe listOf("pokew") - - val dr13 = (st[23] 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!! - (st[26] as FunctionCallStatement).target.nameInSource shouldBe listOf("pokef") - - dr0.chain shouldBe listOf("l1", "s") - dr0.derefLast shouldBe true - dr1.chain shouldBe listOf("l1", "s") - dr1.derefLast shouldBe true - dr2.chain shouldBe listOf("l1", "s") - dr2.derefLast shouldBe true - dr3.chain shouldBe listOf("l1", "s") - dr3.derefLast shouldBe true - dr4.chain shouldBe listOf("l1", "s") - dr4.derefLast shouldBe true - - dr5.chain shouldBe listOf("l1", "s") - dr5.derefLast shouldBe true - dr6.chain shouldBe listOf("l1", "s") - dr6.derefLast shouldBe true - dr7.chain shouldBe listOf("l1", "s") - dr7.derefLast shouldBe true - dr8.chain shouldBe listOf("l1", "s") - dr8.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 - - dr13.chain shouldBe listOf("fptr") - dr13.derefLast shouldBe true - dr15.chain shouldBe listOf("fptr") - dr15.derefLast shouldBe true - - val list0 = (st[27] as Assignment).value as BinaryExpression - val list1 = (st[28] as Assignment).value as BinaryExpression - - list0.operator shouldBe "." - (list0.right as IdentifierReference).nameInSource shouldBe listOf("n") - val list0left = list0.left as ArrayIndexedExpression - list0left.plainarrayvar!!.nameInSource shouldBe listOf("l1") - list0left.indexer.constIndex() shouldBe 0 - list1.operator shouldBe "." - (list1.right as IdentifierReference).nameInSource shouldBe listOf("n") - val list1left = list0.left as ArrayIndexedExpression - list1left.plainarrayvar!!.nameInSource shouldBe listOf("l1") - list1left.indexer.constIndex() shouldBe 0 - } - test("indexing pointers to structs") { val src=""" %import floats @@ -2571,4 +2459,54 @@ main { }""" compileText(VMTarget(), false, src, outputDir, writeAssembly = false) shouldNotBe null } + + test("0-indexed optimizations") { + val src=""" +main { + struct Sprite { + uword x + ubyte y + } + + ^^Sprite[4] @shared sprites + ^^Sprite @shared sprptr + + sub start() { + sprptr.y = 99 + sprptr[0]^^.y = 99 + ;; sprites[0]^^.y = 99 ; no change here. TODO: this syntax doesn't compile yet... + cx16.r0 = &sprptr[0] + + cx16.r2L = sprptr.y + cx16.r0L = sprptr[0].y + cx16.r1L = sprites[0].y ; no change here, need first array element + cx16.r0 = sprites[0] ; no change here, need first array element + cx16.r0 = sprites[0] ; no change here, need first array element + } +}""" + val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = false)!! + val st = result.compilerAst.entrypoint.statements + st.size shouldBe 8 + val a1 = st[0] as Assignment + val a2 = st[1] as Assignment + val a3 = st[2] as Assignment + val a4 = st[3] as Assignment + val a5 = st[4] as Assignment + val a6 = st[5] as Assignment + val a7 = st[6] as Assignment + + a1.target.arrayIndexedDereference shouldBe null + a1.target.pointerDereference!!.chain shouldBe listOf("sprptr", "y") + a2.target.arrayIndexedDereference shouldBe null + a2.target.pointerDereference!!.chain shouldBe listOf("sprptr", "y") + + (a3.value as? AddressOf)?.identifier?.nameInSource shouldBe listOf("sprptr") + (a4.value as? PtrDereference)?.chain shouldBe listOf("sprptr", "y") + (a5.value as? PtrDereference)?.chain shouldBe listOf("sprptr", "y") + val be6 = a6.value as BinaryExpression // this one is an actual array and we need the first element so no change here + be6.operator shouldBe "." + be6.left shouldBe instanceOf() + be6.right shouldBe instanceOf() + (a7.value as? ArrayIndexedExpression)?.indexer?.constIndex() shouldBe 0 + } }) \ No newline at end of file diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 54da4d80b..4579257db 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -5,7 +5,7 @@ TODO STRUCTS and TYPED POINTERS -------------------------- -- make this array indexed assignment work: ^^Node np / np[2]^^.field = 9999 likely needs more support in the assignment target class (remove Note in docs when fixed) +- make this array indexed assignment work: ^^Node np / np[2]^^.field = 9999 (same for pointer arrays!) likely needs more support in the assignment target class (remove Note in docs when fixed) - implement the remaining TODO's in PointerAssignmentsGen. - optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0 - optimize the float copying in assignIndexedPointer() (also word?) diff --git a/examples/test.p8 b/examples/test.p8 index cf7a89333..65c0f3183 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,8 +1,11 @@ main { sub start() { - ubyte @shared ok = sprites[2].y ; this one is fine... - ubyte @shared y = sprites[2].y ; TODO fix crash + ; TODO assigning to pointer indexed is not yet supported: + sprptr[2]^^.y = 99 + sprptr[cx6.r0L]^^.y = 99 + sprites[2]^^.y = 99 + sprites[cx6.r0L]^^.y = 99 } struct Sprite { @@ -12,5 +15,6 @@ main { ^^Sprite[4] @shared sprites + ^^Sprite @shared sprptr }