allow ptr1^^ = ptr^^ (replaces it with memcopy)

This commit is contained in:
Irmen de Jong
2025-05-29 16:34:47 +02:00
parent 112ca3cc53
commit 37ecdc47b3
6 changed files with 123 additions and 54 deletions

View File

@@ -29,6 +29,7 @@ internal class NormalMemSizer(val floatsize: Int): IMemSizer {
dt.isFloat -> floatsize * (numElements ?: 1)
dt.isLong -> 4 * (numElements ?: 1)
dt.isPointer -> 2 // pointer is just a uword
dt.isStructInstance -> dt.subType!!.memsize(this)
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
else -> 2 * (numElements ?: 1)
}

View File

@@ -2367,8 +2367,12 @@ internal class AstChecker(private val program: Program,
}
else if(targetDatatype.isString && sourceDatatype.isUnsignedWord)
errors.err("can't assign uword to str. If the source is a string pointer and you actually want to overwrite the target string, use an explicit strings.copy(src,tgt) instead.", position)
else if(targetDatatype.isStructInstance)
else if(targetDatatype.isStructInstance) {
if(sourceDatatype.isStructInstance && sourceDatatype != targetDatatype)
errors.err("value type $sourceDatatype doesn't match target type $targetDatatype", position)
else
errors.err("assigning to struct instance not supported (use pointers)", position)
}
else
errors.err("value type $sourceDatatype doesn't match target type $targetDatatype", position)

View File

@@ -27,6 +27,7 @@ internal class CodeDesugarer(val program: Program, private val target: ICompilat
// - convert on..goto/call to jumpaddr array and separate goto/call
// - replace implicit pointer dereference chains (a.b.c.d) with explicit ones (a^^.b^^.c^^.d)
// - replace ptr^^ by @(ptr) if ptr is just an uword.
// - replace p1^^ = p2^^ by memcopy.
override fun after(alias: Alias, parent: Node): Iterable<IAstModification> {
return listOf(IAstModification.Remove(alias, parent as IStatementContainer))
@@ -556,4 +557,24 @@ _after:
return noModifications
}
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
val targetDt = assignment.target.inferType(program)
val sourceDt = assignment.value.inferType(program)
if(targetDt.isStructInstance && sourceDt.isStructInstance) {
if(targetDt == sourceDt) {
val size = program.memsizer.memorySize(sourceDt.getOrUndef(), null)
require(program.memsizer.memorySize(targetDt.getOrUndef(), null)==size)
val sourcePtr = IdentifierReference((assignment.value as PtrDereference).chain, assignment.position)
val targetPtr = IdentifierReference(assignment.target.pointerDereference!!.chain, assignment.position)
val numBytes = NumericLiteral.optimalInteger(size, assignment.position)
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assignment.position),
mutableListOf(sourcePtr, targetPtr, numBytes),
false, assignment.position)
return listOf(IAstModification.ReplaceNode(assignment, memcopy, parent))
}
}
return noModifications
}
}

View File

@@ -11,6 +11,7 @@ import prog8.ast.expressions.ArrayIndexedExpression
import prog8.ast.expressions.DirectMemoryRead
import prog8.ast.expressions.PtrDereference
import prog8.ast.statements.Assignment
import prog8.ast.statements.FunctionCallStatement
import prog8.ast.statements.VarDecl
import prog8.code.ast.PtAssignment
import prog8.code.ast.PtReturn
@@ -844,4 +845,71 @@ main {
compileText(VMTarget(), true, src, outputDir) shouldNotBe null
}
test("assigning pointer dereferences via memcopy") {
val src="""
%option enable_floats
main {
sub start() {
struct List {
bool b
word w
float f
^^List next
}
struct Foo {
byte bb
}
^^List l1 = 2000
^^List l2 = 3000
^^Foo f1 = 4000
l1^^ = l2^^
}
}"""
val result = compileText(VMTarget(), false, src, outputDir)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 10
(st[8] as FunctionCallStatement).target.nameInSource shouldBe listOf("sys", "memcopy")
}
test("assigning pointer dereferences should be same type") {
val src="""
%option enable_floats
main {
sub start() {
struct List {
bool b
word w
float f
^^List next
}
struct Foo {
byte bb
}
^^List l1 = 2000
^^List l2 = 3000
^^Foo f1 = 4000
^^bool bptr = 5000
l1^^ = f1^^
l1^^ = bptr^^
l1^^ = 4242
}
}"""
val errors=ErrorReporterForTests()
compileText(VMTarget(), false, src, outputDir, errors=errors)
errors.errors.size shouldBe 3
errors.errors[0] shouldContain "doesn't match"
errors.errors[1] shouldContain "assigning to struct instance not supported"
errors.errors[2] shouldContain "assigning to struct instance not supported"
}
})

View File

@@ -57,10 +57,10 @@ STRUCTS and TYPED POINTERS
- DONE: fix _msb/_lsb storage of the split-words pointer-arrays
- DONE: what about static initialization of an array of struct pointers? -> impossible right now because the pointer values are not constants.
- DONE: make typeForAddressOf() be even more specific about the typed pointers it returns for the address-of operator.
- allow list1^^ = list2^^ (value wise assignment of List structures) by replacing it with a sys.memcopy(list2, list1, sizeof(List)) call.
- DONE: allow list1^^ = list2^^ (value wise assignment of List structures) by replacing it with a sys.memcopy(list2, list1, sizeof(List)) call.
- add unit tests for expected AST elements for all syntaxes dealing with pointers, dereference(chain), derefs, and indexing (both as value and assigntargets)
- fix parse error "barray[2]^^" where barray is ^^bool[10]
- add unit tests for all changes (pointers and structs)
- fix parse error "barray[2]^^" where barray is ^^bool[10]
- try to fix parse error l1^^.s[0] = 4242 (equivalent to l1.s[0]=4242 , which does parse correctly)
- try to make sizeof(^^type) parse correctly (or maybe replace it immediately with sys.SIZEOF_POINTER)
- 6502 codegen: remove checks in checkForPointerTypesOn6502()

View File

@@ -1,13 +1,9 @@
%option enable_floats
%import floats
%import textio
%zeropage basicsafe
main {
sub start() {
bool @shared b
float @shared f
word @shared w
const long ll = 9999999
struct List {
bool b
word w
@@ -15,60 +11,39 @@ main {
^^List next
}
^^List @shared l1
^^float @shared fptr
struct Foo {
byte bb
}
txt.print_ub(sys.SIZEOF_BOOL)
^^List l1 = 2000
^^List l2 = 3000
^^Foo f1 = 4000
l1.b = true
l1.w = 1111
l1.f = 11.234
l2.b = false
l2.w = 2222
l2.f = 222.222
txt.print_uwhex(l1, true)
txt.spc()
txt.print_ub(sys.SIZEOF_WORD)
txt.print_bool(l1.b)
txt.spc()
txt.print_ub(sys.SIZEOF_POINTER)
txt.print_w(l1.w)
txt.spc()
txt.print_ub(sys.SIZEOF_LONG)
txt.spc()
txt.print_ub(sys.SIZEOF_FLOAT)
txt.print_f(l1.f)
txt.nl()
txt.print_ub(sizeof(true))
l1^^ = l2^^
txt.print_uwhex(l1, true)
txt.spc()
txt.print_ub(sizeof(1234))
txt.print_bool(l1.b)
txt.spc()
txt.print_ub(sizeof(12345678))
txt.print_w(l1.w)
txt.spc()
txt.print_ub(sizeof(9.999))
txt.nl()
txt.print_ub(sizeof(b))
txt.spc()
txt.print_ub(sizeof(w))
txt.spc()
txt.print_ub(sizeof(ll))
txt.spc()
txt.print_ub(sizeof(f))
txt.spc()
txt.print_ub(sizeof(l1))
txt.spc()
txt.print_ub(sizeof(fptr^^))
txt.spc()
txt.print_ub(sizeof(l1^^))
txt.nl()
txt.print_ub(sizeof(bool))
txt.spc()
txt.print_ub(sizeof(word))
txt.spc()
txt.print_ub(sizeof(long))
txt.spc()
txt.print_ub(sizeof(float))
txt.spc()
txt.print_ub(sizeof(List))
txt.spc()
txt.print_ub(sizeof(&w))
txt.spc()
; txt.print_ub(sizeof(^^float)) ; TODO parse this
; txt.spc()
; txt.print_ub(sizeof(^^List)) ; TODO parse this
; txt.spc()
txt.print_f(l1.f)
txt.nl()
}
}