From fdbbd181ea4d91cc7bba7183a0b90613cc4962c6 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 17 Jan 2024 22:51:11 +0100 Subject: [PATCH] fixes for address-of uword pointer array expressions --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 3 +- .../cpu6502/assignment/AssignmentAsmGen.kt | 2 +- .../optimizer/ConstantIdentifierReplacer.kt | 30 +++++++---- .../src/prog8/buildversion/BuildVersion.kt | 12 ++--- .../compiler/astprocessing/AstChecker.kt | 6 ++- compiler/test/ast/TestConst.kt | 53 +++++++++++-------- .../prog8/ast/expressions/AstExpressions.kt | 11 ++-- docs/source/todo.rst | 1 - 8 files changed, 74 insertions(+), 44 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 0b64cfb96..45dbcd1b1 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -198,7 +198,8 @@ private fun PtIdentifier.prefix(parent: PtNode, st: SymbolTable): PtIdentifier { StNodeType.BLOCK -> 'b' StNodeType.SUBROUTINE, StNodeType.ROMSUB -> 's' StNodeType.LABEL -> 'l' - StNodeType.STATICVAR, StNodeType.MEMVAR, StNodeType.CONSTANT -> 'v' + StNodeType.STATICVAR, StNodeType.MEMVAR -> 'v' + StNodeType.CONSTANT -> 'c' StNodeType.BUILTINFUNC -> 's' StNodeType.MEMORYSLAB -> 'v' else -> '?' diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 3a8224381..7a2ee1a7c 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -2512,7 +2512,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, else program.memsizer.memorySize(arrayDt!!, constIndex) // add arrayIndexExpr * elementsize to the address of the array variable. } else { - val eltSize = program.memsizer.memorySize(ArrayToElementTypes.getValue(arrayDt!!)) + val eltSize = if(arrayDt==DataType.UWORD) 1 else program.memsizer.memorySize(ArrayToElementTypes.getValue(arrayDt!!)) assignExpressionToVariable(arrayIndexExpr, "P8ZP_SCRATCH_W1", DataType.UWORD) when(eltSize) { 1 -> {} diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index 93187064b..1487b8dec 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -272,6 +272,14 @@ class VarConstantValueTypeAdjuster( // This is needed because further constant optimizations depend on those. internal class ConstantIdentifierReplacer(private val program: Program, private val errors: IErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() { + override fun before(addressOf: AddressOf, parent: Node): Iterable { + val constValue = addressOf.constValue(program) + if(constValue!=null) { + return listOf(IAstModification.ReplaceNode(addressOf, constValue, parent)) + } + return noModifications + } + override fun after(identifier: IdentifierReference, parent: Node): Iterable { // replace identifiers that refer to const value, with the value itself // if it's a simple type and if it's not a left hand side variable @@ -304,16 +312,20 @@ internal class ConstantIdentifierReplacer(private val program: Program, private listOf(IAstModification.ReplaceNode(arrayIdx, memread, arrayIdx.parent)) } } - return when (cval.type) { - in NumericDatatypes -> listOf( - IAstModification.ReplaceNode( - identifier, - NumericLiteral(cval.type, cval.number, identifier.position), - identifier.parent + when (cval.type) { + in NumericDatatypes -> { + if(parent is AddressOf) + return noModifications // cannot replace the identifier INSIDE the addr-of here, let's do it later. + return listOf( + IAstModification.ReplaceNode( + identifier, + NumericLiteral(cval.type, cval.number, identifier.position), + identifier.parent + ) ) - ) + } in PassByReferenceDatatypes -> throw InternalCompilerException("pass-by-reference type should not be considered a constant") - else -> noModifications + else -> return noModifications } } catch (x: UndefinedSymbolError) { errors.err(x.message, x.position) @@ -321,7 +333,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private } } - override fun before(decl: VarDecl, parent: Node): Iterable { + override fun after(decl: VarDecl, parent: Node): Iterable { // the initializer value can't refer to the variable itself (recursive definition) if(decl.value?.referencesIdentifier(listOf(decl.name)) == true || decl.arraysize?.indexExpr?.referencesIdentifier(listOf(decl.name)) == true) { errors.err("recursive var declaration", decl.position) diff --git a/compiler/src/prog8/buildversion/BuildVersion.kt b/compiler/src/prog8/buildversion/BuildVersion.kt index 35b6f5724..bca8a5e49 100644 --- a/compiler/src/prog8/buildversion/BuildVersion.kt +++ b/compiler/src/prog8/buildversion/BuildVersion.kt @@ -5,11 +5,11 @@ package prog8.buildversion */ const val MAVEN_GROUP = "prog8" const val MAVEN_NAME = "compiler" -const val VERSION = "9.8-SNAPSHOT" -const val GIT_REVISION = 4335 -const val GIT_SHA = "44d82f9190763aa5113a3dce4a7d4623018a1c25" -const val GIT_DATE = "2023-12-28T12:30:07Z" +const val VERSION = "10.0-SNAPSHOT" +const val GIT_REVISION = 4405 +const val GIT_SHA = "69075376dc26f06b7422f47529f90577f4213aaf" +const val GIT_DATE = "2024-01-17T20:24:41Z" const val GIT_BRANCH = "master" -const val BUILD_DATE = "2023-12-28T12:44:26Z" -const val BUILD_UNIX_TIME = 1703767466828L +const val BUILD_DATE = "2024-01-17T21:46:56Z" +const val BUILD_UNIX_TIME = 1705528016840L const val DIRTY = 1 diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index b0cdf63d8..6e0410c0c 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -592,8 +592,10 @@ internal class AstChecker(private val program: Program, override fun visit(addressOf: AddressOf) { checkLongType(addressOf) val variable=addressOf.identifier.targetVarDecl(program) - if(variable!=null && variable.type==VarDeclType.CONST) - errors.err("invalid pointer-of operand type", addressOf.position) + if(variable!=null && variable.type==VarDeclType.CONST && addressOf.arrayIndex==null) errors.err( + "invalid pointer-of operand type", + addressOf.position + ) super.visit(addressOf) } diff --git a/compiler/test/ast/TestConst.kt b/compiler/test/ast/TestConst.kt index 006cc9475..0c1f51ed2 100644 --- a/compiler/test/ast/TestConst.kt +++ b/compiler/test/ast/TestConst.kt @@ -4,6 +4,7 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.types.instanceOf +import prog8.ast.expressions.AddressOf import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteral @@ -15,7 +16,6 @@ import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target import prog8.code.target.Cx16Target -import prog8.code.target.VMTarget import prog8tests.helpers.compileText class TestConst: FunSpec({ @@ -219,22 +219,6 @@ class TestConst: FunSpec({ (initY2.value as NumericLiteral).number shouldBe 11.0 } - test("const eval of address-of a memory mapped variable") { - val src = """ -main { - sub start() { - &ubyte mappedvar = 1000 - cx16.r0 = &mappedvar - &ubyte[8] array = &mappedvar - cx16.r0 = &array - - const uword HIGH_MEMORY_START = 40960 - &uword[20] @shared wa = HIGH_MEMORY_START - } -}""" - compileText(VMTarget(), optimize=false, src, writeAssembly=false) shouldNotBe null - } - test("const pointer variable indexing works") { val src=""" main { @@ -295,21 +279,48 @@ main { ((st[5] as Assignment).value as NumericLiteral).number shouldBe 0x9e00+2*30 } + test("address of a memory mapped variable") { + val src = """ +main { + sub start() { + &ubyte mappedvar = 1000 + cx16.r0 = &mappedvar + &ubyte[8] array = &mappedvar + cx16.r0 = &array + + const uword HIGH_MEMORY_START = 40960 + &uword[20] @shared wa = HIGH_MEMORY_START + } +}""" + val result = compileText(Cx16Target(), optimize=false, src, writeAssembly=true)!! + val st = result.compilerAst.entrypoint.statements + st.size shouldBe 7 + val arrayDeclV = (st[2] as VarDecl).value + (arrayDeclV as NumericLiteral).number shouldBe 1000.0 + val waDeclV = (st[5] as VarDecl).value + (waDeclV as NumericLiteral).number shouldBe 40960.0 + } + test("address of a const uword pointer array expression") { val src=""" main { sub start() { const uword buffer = ${'$'}2000 - uword addr = &buffer[2] + uword @shared addr = &buffer[2] const ubyte width = 100 ubyte @shared i ubyte @shared j - uword addr2 = &buffer[i * width + j] + uword @shared addr2 = &buffer[i * width + j] } }""" - val result = compileText(Cx16Target(), true, src, writeAssembly = false)!! + val result = compileText(Cx16Target(), true, src, writeAssembly = true)!! val st = result.compilerAst.entrypoint.statements - st.size shouldBe 9999 + st.size shouldBe 11 + val assignAddr = (st[2] as Assignment).value + (assignAddr as NumericLiteral).number shouldBe 8194.0 + val assignAddr2 = ((st[9] as Assignment).value as AddressOf) + assignAddr2.identifier.nameInSource shouldBe listOf("buffer") + assignAddr2.arrayIndex!!.indexExpr shouldBe instanceOf() } }) diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index fc9cafe8d..95b588e1c 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -407,13 +407,18 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), position) override fun constValue(program: Program): NumericLiteral? { val target = this.identifier.targetStatement(program) as? VarDecl - if(target?.type==VarDeclType.MEMORY) { + if(target?.type==VarDeclType.MEMORY || target?.type==VarDeclType.CONST) { var address = target.value?.constValue(program)?.number if(address!=null) { if(arrayIndex!=null) { val index = arrayIndex?.constIndex() - if (index != null) - address += program.memsizer.memorySize(target.datatype, index) + if (index != null) { + address += when (target.datatype) { + DataType.UWORD -> index + in ArrayDatatypes -> program.memsizer.memorySize(target.datatype, index) + else -> throw FatalAstException("need array or uword ptr") + } + } else return null } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 43697a5a1..f1c0b319c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,6 @@ TODO ==== -2 unit tests that are failing. Mark had a compiler crash FatalAstException: invalid dt. IR: optimize funcRolRor()