Skip to content

Commit eae716b

Browse files
authored
Merge pull request #963 from boriel-basic/fix/strange_array_behavior
Fix/strange array behavior
2 parents 95c18a8 + 98ed764 commit eae716b

File tree

91 files changed

+1791
-1551
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+1791
-1551
lines changed

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: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,22 @@ def visit_FUNCTION(self, node):
5555
# if self.O_LEVEL > 1:
5656
# return
5757

58+
if local_var.class_ == CLASS.const or local_var.scope == SCOPE.parameter:
59+
continue
60+
5861
if local_var.class_ == CLASS.array and local_var.scope == SCOPE.local:
59-
bound_ptrs = [] # Bound tables pointers (empty if not used)
6062
lbound_label = local_var.mangled + ".__LBOUND__"
6163
ubound_label = local_var.mangled + ".__UBOUND__"
64+
lbound_needed = not local_var.is_zero_based and local_var.is_dynamically_accessed
6265

63-
if local_var.lbound_used or local_var.ubound_used:
64-
bound_ptrs = ["0", "0"] # NULL by default
65-
if local_var.lbound_used:
66-
bound_ptrs[0] = lbound_label
67-
if local_var.ubound_used:
68-
bound_ptrs[1] = ubound_label
66+
bound_ptrs = [lbound_label if lbound_needed else "0", "0"]
67+
if local_var.ubound_used:
68+
bound_ptrs[1] = ubound_label
6969

70-
if bound_ptrs:
70+
if bound_ptrs != ["0", "0"]:
7171
OPTIONS["__DEFINES"].value["__ZXB_USE_LOCAL_ARRAY_WITH_BOUNDS__"] = ""
7272

73-
if local_var.lbound_used:
73+
if lbound_needed:
7474
l = ["%04X" % bound.lower for bound in local_var.bounds]
7575
bound_tables.append(LabelledData(lbound_label, l))
7676

@@ -89,8 +89,7 @@ def visit_FUNCTION(self, node):
8989
if local_var.default_value is not None:
9090
r.extend(self.array_default_value(local_var.type_, local_var.default_value))
9191
self.ic_larrd(local_var.offset, q, local_var.size, r, bound_ptrs) # Initializes array bounds
92-
elif local_var.class_ == CLASS.const or local_var.scope == SCOPE.parameter:
93-
continue
92+
9493
else: # Local vars always defaults to 0, so if 0 we do nothing
9594
if (
9695
local_var.token != "FUNCTION"
@@ -119,6 +118,7 @@ def visit_FUNCTION(self, node):
119118
if local_var.type_ == self.TYPE(TYPE.string):
120119
if local_var.class_ == CLASS.const or local_var.token == "FUNCTION":
121120
continue
121+
122122
# Only if it's string we free it
123123
if local_var.class_ != CLASS.array: # Ok just free it
124124
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):

src/arch/z80/visitor/translator.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
from src.symbols.id_ import ref
2626
from src.symbols.type_ import Type
2727

28-
__all__ = ("Translator",)
28+
__all__ = (
29+
"LabelledData",
30+
"Translator",
31+
)
2932

3033
LabelledData = namedtuple("LabelledData", ("label", "data"))
3134

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 and entry.is_dynamically_accessed:
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/zx48k/runtime/bound.asm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ __CONT:
7070
ld h, (hl)
7171
ld l, a ; LD HL, (HL) => Origin of L/U Bound table
7272

73+
; for LBound only, HL = 0x0000 (NULL) if the array is all 0-based
74+
or h
75+
ret z ; Should never happen for UBound
76+
7377
add hl, de ; hl += OFFSET __LBOUND._xxxx
7478
ld e, (hl) ; de = (hl)
7579
inc hl

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/arrayaccess.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class SymbolARRAYACCESS(SymbolCALL):
3535
def __init__(self, entry, arglist: SymbolARGLIST, lineno: int, filename: str):
3636
super().__init__(entry, arglist, lineno, filename)
3737
assert all(gl.BOUND_TYPE == x.type_.type_ for x in arglist), "Invalid type for array index"
38+
self.entry.ref.is_dynamically_accessed = True
3839

3940
@property
4041
def entry(self):
@@ -90,6 +91,12 @@ def offset(self) -> int | None:
9091
offset *= self.type_.size
9192
return offset
9293

94+
@cached_property
95+
def is_constant(self) -> bool:
96+
"""Whether this array access is constant.
97+
e.g. A(1) is constant. A(i) is not."""
98+
return self.offset is None
99+
93100
@classmethod
94101
def make_node(cls, id_: str, arglist: SymbolARGLIST, lineno: int, filename: str) -> Optional["SymbolARRAYACCESS"]:
95102
"""Creates an array access. A(x1, x2, ..., xn)"""

src/symbols/id_/_id.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,7 @@ class SymbolID(SymbolIdABC):
4040
"declared",
4141
"filename",
4242
"has_address",
43-
"lineno",
44-
"mangled",
45-
"name",
4643
"original_name",
47-
"scope",
4844
"scope_ref",
4945
)
5046

src/symbols/id_/interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
class SymbolIdABC(Symbol, ABC):
9-
__slots__ = ()
9+
__slots__ = "lineno", "mangled", "name", "scope"
1010

1111
scope: SCOPE
1212
name: str

0 commit comments

Comments
 (0)