Skip to content

Commit d12de69

Browse files
committed
fix: update LBounds tables
LBound PTR MUST always be allocated in the stack. If it's a zero-based array, it just contains a NULL (0x0000) pointer. The Array alloc routine will not use the ubound pointer if it's 0.
1 parent 1c198ad commit d12de69

6 files changed

Lines changed: 37 additions & 25 deletions

File tree

src/arch/z80/backend/generic.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,13 @@ def _larrd(ins: Quad):
272272
if not isinstance(bounds, list) or len(bounds) not in (0, 2):
273273
raise InvalidIC(ins, "Bounds list length must be 0 or 2, not %s" % ins[5])
274274

275-
if bounds:
275+
have_bounds = bounds and any(x != "0" for x in bounds)
276+
if have_bounds:
276277
output.extend(
277278
[
278-
"ld hl, %s" % bounds[1],
279+
"ld hl, %s" % bounds[1], # UBOUND Table PTR
279280
"push hl",
280-
"ld hl, %s" % bounds[0],
281+
"ld hl, %s" % bounds[0], # LBOUND Table PTR
281282
"push hl",
282283
]
283284
)
@@ -297,12 +298,12 @@ def _larrd(ins: Quad):
297298
)
298299

299300
if must_initialize:
300-
if not bounds:
301+
if not have_bounds:
301302
output.append(runtime_call(RuntimeLabel.ALLOC_INITIALIZED_LOCAL_ARRAY))
302303
else:
303304
output.append(runtime_call(RuntimeLabel.ALLOC_INITIALIZED_LOCAL_ARRAY_WITH_BOUNDS))
304305
else:
305-
if not bounds:
306+
if not have_bounds:
306307
output.append(runtime_call(RuntimeLabel.ALLOC_LOCAL_ARRAY))
307308
else:
308309
output.append(runtime_call(RuntimeLabel.ALLOC_LOCAL_ARRAY_WITH_BOUNDS))

src/arch/z80/visitor/function_translator.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,17 @@ def visit_FUNCTION(self, node):
5959
continue
6060

6161
if local_var.class_ == CLASS.array and local_var.scope == SCOPE.local:
62-
bound_ptrs = [] # Bound tables pointers (empty if not used)
6362
lbound_label = local_var.mangled + ".__LBOUND__"
6463
ubound_label = local_var.mangled + ".__UBOUND__"
6564

66-
if local_var.lbound_used or local_var.ubound_used:
67-
bound_ptrs = ["0", "0"] # NULL by default
68-
if local_var.lbound_used:
69-
bound_ptrs[0] = lbound_label
70-
if local_var.ubound_used:
71-
bound_ptrs[1] = ubound_label
65+
bound_ptrs = ["0" if local_var.is_zero_based else lbound_label, "0"]
66+
if local_var.ubound_used:
67+
bound_ptrs[1] = ubound_label
7268

73-
if bound_ptrs:
69+
if bound_ptrs != ["0", "0"]:
7470
OPTIONS["__DEFINES"].value["__ZXB_USE_LOCAL_ARRAY_WITH_BOUNDS__"] = ""
7571

76-
if local_var.lbound_used:
72+
if not local_var.is_zero_based:
7773
l = ["%04X" % bound.lower for bound in local_var.bounds]
7874
bound_tables.append(LabelledData(lbound_label, l))
7975

@@ -121,6 +117,7 @@ def visit_FUNCTION(self, node):
121117
if local_var.type_ == self.TYPE(TYPE.string):
122118
if local_var.class_ == CLASS.const or local_var.token == "FUNCTION":
123119
continue
120+
124121
# Only if it's string we free it
125122
if local_var.class_ != CLASS.array: # Ok just free it
126123
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):

src/arch/z80/visitor/var_translator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ def visit_ARRAYDECL(self, node):
4646

4747
lbound_label = entry.mangled + ".__LBOUND__"
4848
ubound_label = entry.mangled + ".__UBOUND__"
49-
50-
is_zero_based_array = all(bound.lower == 0 for bound in node.bounds)
5149
bound_ptrs = ["0", "0"] # NULL by default
52-
if entry.lbound_used or not is_zero_based_array:
50+
51+
if not entry.is_zero_based:
5352
bound_ptrs[0] = lbound_label
53+
5454
if entry.ubound_used or OPTIONS.array_check:
5555
bound_ptrs[1] = ubound_label
5656

src/lib/arch/zx48k/runtime/array/arrayalloc.asm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ __ALLOC_LOCAL_ARRAY:
4141
; ---------------------------------------------------------------------
4242
; __ALLOC_INITIALIZED_LOCAL_ARRAY
4343
; Allocates an array element area in the heap, and clears it filling it
44-
; with 0 bytes
44+
; with data whose pointer (PTR) is in the stack
4545
;
4646
; Parameters
4747
; HL = Offset to be added to IX => HL = IX + HL
@@ -99,12 +99,15 @@ __ALLOC_LOCAL_ARRAY_WITH_BOUNDS2:
9999
ld (hl), e
100100
inc hl
101101
ld (hl), d
102-
pop de
102+
pop de ;; PTR to ubound table
103+
push bc ;; puts ret address back
104+
ld a, d
105+
or e
106+
ret z ;; if PTR for UBound is 0, it's not used
103107
inc hl
104108
ld (hl), e
105109
inc hl
106110
ld (hl), d
107-
push bc
108111
ret
109112

110113

src/lib/arch/zxnext/runtime/array/arrayalloc.asm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ __ALLOC_LOCAL_ARRAY:
4141
; ---------------------------------------------------------------------
4242
; __ALLOC_INITIALIZED_LOCAL_ARRAY
4343
; Allocates an array element area in the heap, and clears it filling it
44-
; with 0 bytes
44+
; with data whose pointer (PTR) is in the stack
4545
;
4646
; Parameters
4747
; HL = Offset to be added to IX => HL = IX + HL
@@ -99,12 +99,15 @@ __ALLOC_LOCAL_ARRAY_WITH_BOUNDS2:
9999
ld (hl), e
100100
inc hl
101101
ld (hl), d
102-
pop de
102+
pop de ;; PTR to ubound table
103+
push bc ;; puts ret address back
104+
ld a, d
105+
or e
106+
ret z ;; if PTR for UBound is 0, it's not used
103107
inc hl
104108
ld (hl), e
105109
inc hl
106110
ld (hl), d
107-
push bc
108111
ret
109112

110113

src/symbols/id_/ref/arrayref.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,16 @@ def size(self):
3939

4040
@property
4141
def memsize(self):
42-
"""Total array cell + indexes size"""
43-
return (2 + (2 if self.lbound_used or self.ubound_used else 0)) * TYPE.size(gl.PTR_TYPE)
42+
"""Total array cell + indexes size
43+
The current implementation of an array is a struct with the following information:
44+
45+
- PTR to DIM sizes table
46+
- PTR to Array DATA region
47+
- PTR to LBound Tables (always required; 0 for 0 based arrays)
48+
- PTR to UBound Tables (always required, even if not used)
49+
"""
50+
ptr_size = TYPE.size(gl.PTR_TYPE) # Size of a pointer for the selected arch
51+
return ptr_size * (3 + self.ubound_used)
4452

4553
@property
4654
def data_label(self) -> str:

0 commit comments

Comments
 (0)