mirror of
https://github.com/irmen/prog8.git
synced 2026-04-26 20:17:57 +00:00
support a few other simple cases of struct instance assignment
This commit is contained in:
@@ -742,6 +742,8 @@ _after:
|
||||
if(targetDt.isStructInstance && sourceDt.isStructInstance) {
|
||||
if(targetDt == sourceDt) {
|
||||
// special case simple struct instance assignment via memory copy
|
||||
val size = program.memsizer.memorySize(sourceDt.getOrUndef(), null)
|
||||
val structSizeNum = NumericLiteral.optimalInteger(size, assignment.position)
|
||||
val deref = assignment.value as? PtrDereference
|
||||
if(deref!=null) {
|
||||
val sourcePtr = IdentifierReference(deref.chain, assignment.position)
|
||||
@@ -749,15 +751,50 @@ _after:
|
||||
if(targetDeref!=null) {
|
||||
// ptr1^^ = ptr2^^ --> memcopy(ptr2, ptr1, sizeof(struct))
|
||||
val targetPtr = IdentifierReference(targetDeref.chain, assignment.position)
|
||||
val size = program.memsizer.memorySize(sourceDt.getOrUndef(), null)
|
||||
require(program.memsizer.memorySize(targetDt.getOrUndef(), null)==size)
|
||||
val numBytes = NumericLiteral.optimalInteger(size, assignment.position)
|
||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assignment.position),
|
||||
mutableListOf(sourcePtr, targetPtr, numBytes),
|
||||
mutableListOf(sourcePtr, targetPtr, structSizeNum),
|
||||
false, assignment.position)
|
||||
return listOf(IAstModification.ReplaceNode(assignment, memcopy, parent))
|
||||
}
|
||||
val targetIdx = assignment.target.arrayindexed
|
||||
if(targetIdx!=null) {
|
||||
val constIndex = targetIdx.indexer.constIndex()
|
||||
if(constIndex!=null) {
|
||||
val idxType = targetIdx.inferType(program)
|
||||
if (idxType.isStructInstance) {
|
||||
// ptr1[idx]^^ = ptr2^^ --> memcopy(ptr2, ptr1+idx*sizeof(struct), sizseof(struct))
|
||||
val offset = NumericLiteral.optimalInteger(constIndex * size, assignment.position)
|
||||
val target = BinaryExpression(targetIdx.plainarrayvar!!, "+", offset, assignment.position)
|
||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assignment.position),
|
||||
mutableListOf(sourcePtr, target, structSizeNum),
|
||||
false, assignment.position)
|
||||
return listOf(IAstModification.ReplaceNode(assignment, memcopy, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sourceIdx = assignment.value as? ArrayIndexedExpression
|
||||
if(sourceIdx!=null) {
|
||||
val constIndex = sourceIdx.indexer.constIndex()
|
||||
if(constIndex!=null) {
|
||||
val idxType = sourceIdx.inferType(program)
|
||||
if(idxType.isStructInstance) {
|
||||
val targetDeref = assignment.target.pointerDereference
|
||||
if(targetDeref!=null) {
|
||||
// ptr1^^ = ptr2[idx] --> memcopy(ptr2 + idx*sizeof(struct), ptr1, sizeof(struct))
|
||||
val offset = NumericLiteral.optimalInteger(constIndex * size, assignment.position)
|
||||
val targetPtr = IdentifierReference(targetDeref.chain, assignment.position)
|
||||
val source = BinaryExpression(sourceIdx.plainarrayvar!!, "+", offset, assignment.position)
|
||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assignment.position),
|
||||
mutableListOf(source, targetPtr, structSizeNum),
|
||||
false, assignment.position)
|
||||
return listOf(IAstModification.ReplaceNode(assignment, memcopy, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO support other forms of struct instance assignments, such as ptr^^ = array[2]^^ , array[3] = array[2], array[3] = ptr^^
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1203,6 +1203,33 @@ main {
|
||||
errors.errors[3] shouldContain "assigning this value to struct instance not supported"
|
||||
}
|
||||
|
||||
xtest("assigning struct instances") {
|
||||
val src="""
|
||||
main {
|
||||
sub start() {
|
||||
struct List {
|
||||
bool b
|
||||
uword value
|
||||
float fv
|
||||
} ; sizeof = 11
|
||||
|
||||
^^List lp1 = 10000
|
||||
^^List lp2 = 20000
|
||||
|
||||
lp2^^ = lp1^^ ; memcopy(lp1, lp2, 11)
|
||||
lp2[2] = lp1^^ ; memcopy(lp1, lp2 + 22, 11)
|
||||
lp2[2]^^ = lp1^^ ; memcopy(lp1, lp2 + 22, 11) (same as above) TODO fix astchecker to allow this case
|
||||
lp2^^ = lp1[2] ; memcopy(lp1 + 22, lp2, 11)
|
||||
lp2^^ = lp1[2]^^ ; memcopy(lp1 + 22, lp2, 11) (same as above) TODO fix astchecker to allow this case
|
||||
lp2[3] = lp1[2] ; memcopy(lp1 + 22, lp2 + 33, 11) TODO fix astchecker to allow this case
|
||||
}
|
||||
}"""
|
||||
val errors = ErrorReporterForTests()
|
||||
val result = compileText(VMTarget(), false, src, outputDir, errors=errors)!!
|
||||
val st = result.compilerAst.entrypoint.statements
|
||||
st.size shouldBe 99
|
||||
}
|
||||
|
||||
test("a.b.c[i]^^.value as expression where pointer is struct") {
|
||||
val src="""
|
||||
main {
|
||||
@@ -1870,17 +1897,15 @@ main {
|
||||
^^Node nodes
|
||||
n1^^=n2^^ ; ok
|
||||
bptr1^^=bptr2^^ ; ok
|
||||
n2 = nodes[2]^^ ; cannot assign instance to pointer
|
||||
n1^^=nodes[2] ; cannot assign struct instances like this
|
||||
n1^^=nodes[2] ; ok
|
||||
n2 = nodes[2]^^ ; cannot assign instance to pointer like this yet
|
||||
}
|
||||
}"""
|
||||
val errors=ErrorReporterForTests(keepMessagesAfterReporting = true)
|
||||
compileText(VMTarget(), false, src, outputDir, errors=errors) shouldBe null
|
||||
errors.errors.size shouldBe 4
|
||||
errors.errors.size shouldBe 2
|
||||
errors.errors[0] shouldContain "struct instance by value"
|
||||
errors.errors[1] shouldContain "no support for getting the target value of pointer array indexing"
|
||||
errors.errors[2] shouldContain "struct instance by value"
|
||||
errors.errors[3] shouldContain "assigning this value to struct instance not supported"
|
||||
}
|
||||
|
||||
test("pointer variable usage detection in other block 1") {
|
||||
|
||||
@@ -151,11 +151,14 @@ The struct type creates a new name scape, so accessing the fields of a struct is
|
||||
.. note::
|
||||
Structs are only supported as a *reference type* (via a pointer). It is currently not possible to use them as a value type.
|
||||
This means you cannot create an array of structs either - only arrays of pointers to structs.
|
||||
There is one simple case where the compiler allows assignment of struct instances. You are allowed to write::
|
||||
There are a couple of simple case where the compiler allows assignment of struct instances. You are allowed to write::
|
||||
|
||||
ptr1^^ = ptr2^^ ; set what ptr1 points to, to the contents of what ptr2 points to
|
||||
ptr2^^ = ptr1^^
|
||||
ptr2^^ = ptr1[2]
|
||||
ptr2[2] = ptr1^^
|
||||
|
||||
The compiler replaces this with a memory copy if these are pointers to a struct.
|
||||
In the future more cases may be supported.
|
||||
|
||||
.. note::
|
||||
Using structs instead of plain arrays may result in less efficent code being generated.
|
||||
|
||||
@@ -5,7 +5,6 @@ STRUCTS and TYPED POINTERS (6502 codegen specific)
|
||||
--------------------------------------------------
|
||||
|
||||
- implement the TODO's in PointerAssignmentsGen.
|
||||
- implement some more struct instance assignments (via memcopy) in CodeDesugarer (see the TODO)
|
||||
- scan through 6502 library modules to change untyped uword pointers to typed pointers
|
||||
- scan through 6502 examples to change untyped uword pointers to typed pointers
|
||||
- fix code size regressions (if any left)
|
||||
@@ -14,3 +13,4 @@ STRUCTS and TYPED POINTERS (6502 codegen specific)
|
||||
- optimize deref() when field offset is 0, don't use a temporary at all if the var is in zp already (maybe already solved by the previous one?)
|
||||
- optimize the multiplications in assignAddressOfIndexedPointer()
|
||||
- optimize the float copying in assignIndexedPointer() (also word?)
|
||||
- implement some more struct instance assignments (via memcopy) in CodeDesugarer (see the TODO) (add to documentation as well, paragraph 'Structs')
|
||||
|
||||
+15
-24
@@ -6,36 +6,27 @@
|
||||
|
||||
|
||||
main {
|
||||
|
||||
struct List {
|
||||
^^uword s
|
||||
ubyte n
|
||||
^^List next
|
||||
}
|
||||
|
||||
sub start() {
|
||||
ubyte[10] array
|
||||
uword @shared wordptr
|
||||
^^bool @shared boolptr
|
||||
^^float @shared floatptr
|
||||
^^byte @shared byteptr
|
||||
^^ubyte @shared ubyteptr
|
||||
^^List @shared listptr
|
||||
^^List @shared listptr2
|
||||
struct List {
|
||||
bool b
|
||||
uword value
|
||||
float fv
|
||||
} ; sizeof = 11
|
||||
|
||||
bool @shared zz
|
||||
float @shared fl
|
||||
byte @shared bb
|
||||
^^List lp1 = 10000
|
||||
^^List lp2 = 20000
|
||||
|
||||
zz = boolptr[999]
|
||||
fl = floatptr[999]
|
||||
bb = byteptr[999]
|
||||
cx16.r0L = ubyteptr[999]
|
||||
cx16.r1L = wordptr[999]
|
||||
cx16.r2L = array[9]
|
||||
lp2^^ = lp1^^ ; memcopy(lp1, lp2, 11)
|
||||
lp2[2] = lp1^^ ; memcopy(lp1, lp2 + 22, 11)
|
||||
; lp2[2]^^ = lp1^^ ; memcopy(lp1, lp2 + 22, 11) (same as above) TODO fix astchecker to allow this case
|
||||
lp2^^ = lp1[2] ; memcopy(lp1 + 22, lp2, 11)
|
||||
; lp2^^ = lp1[2]^^ ; memcopy(lp1 + 22, lp2, 11) (same as above) TODO fix astchecker to allow this case
|
||||
; lp2[3] = lp1[2] ; memcopy(lp1 + 22, lp2 + 33, 11) TODO fix astchecker to allow this case
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
;main {
|
||||
; sub start() {
|
||||
; floatprob()
|
||||
|
||||
Reference in New Issue
Block a user