Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/arch/z80/backend/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,13 @@ def _larrd(ins: Quad):
if not isinstance(bounds, list) or len(bounds) not in (0, 2):
raise InvalidIC(ins, "Bounds list length must be 0 or 2, not %s" % ins[5])

if bounds:
have_bounds = bounds and any(x != "0" for x in bounds)
if have_bounds:
output.extend(
[
"ld hl, %s" % bounds[1],
"ld hl, %s" % bounds[1], # UBOUND Table PTR
"push hl",
"ld hl, %s" % bounds[0],
"ld hl, %s" % bounds[0], # LBOUND Table PTR
"push hl",
]
)
Expand All @@ -297,12 +298,12 @@ def _larrd(ins: Quad):
)

if must_initialize:
if not bounds:
if not have_bounds:
output.append(runtime_call(RuntimeLabel.ALLOC_INITIALIZED_LOCAL_ARRAY))
else:
output.append(runtime_call(RuntimeLabel.ALLOC_INITIALIZED_LOCAL_ARRAY_WITH_BOUNDS))
else:
if not bounds:
if not have_bounds:
output.append(runtime_call(RuntimeLabel.ALLOC_LOCAL_ARRAY))
else:
output.append(runtime_call(RuntimeLabel.ALLOC_LOCAL_ARRAY_WITH_BOUNDS))
Expand Down
22 changes: 11 additions & 11 deletions src/arch/z80/visitor/function_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,22 @@ def visit_FUNCTION(self, node):
# if self.O_LEVEL > 1:
# return

if local_var.class_ == CLASS.const or local_var.scope == SCOPE.parameter:
continue

if local_var.class_ == CLASS.array and local_var.scope == SCOPE.local:
bound_ptrs = [] # Bound tables pointers (empty if not used)
lbound_label = local_var.mangled + ".__LBOUND__"
ubound_label = local_var.mangled + ".__UBOUND__"
lbound_needed = not local_var.is_zero_based and local_var.is_dynamically_accessed

if local_var.lbound_used or local_var.ubound_used:
bound_ptrs = ["0", "0"] # NULL by default
if local_var.lbound_used:
bound_ptrs[0] = lbound_label
if local_var.ubound_used:
bound_ptrs[1] = ubound_label
bound_ptrs = [lbound_label if lbound_needed else "0", "0"]
if local_var.ubound_used:
bound_ptrs[1] = ubound_label

if bound_ptrs:
if bound_ptrs != ["0", "0"]:
OPTIONS["__DEFINES"].value["__ZXB_USE_LOCAL_ARRAY_WITH_BOUNDS__"] = ""

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

Expand All @@ -89,8 +89,7 @@ def visit_FUNCTION(self, node):
if local_var.default_value is not None:
r.extend(self.array_default_value(local_var.type_, local_var.default_value))
self.ic_larrd(local_var.offset, q, local_var.size, r, bound_ptrs) # Initializes array bounds
elif local_var.class_ == CLASS.const or local_var.scope == SCOPE.parameter:
continue

else: # Local vars always defaults to 0, so if 0 we do nothing
if (
local_var.token != "FUNCTION"
Expand Down Expand Up @@ -119,6 +118,7 @@ def visit_FUNCTION(self, node):
if local_var.type_ == self.TYPE(TYPE.string):
if local_var.class_ == CLASS.const or local_var.token == "FUNCTION":
continue

# Only if it's string we free it
if local_var.class_ != CLASS.array: # Ok just free it
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):
Expand Down
5 changes: 4 additions & 1 deletion src/arch/z80/visitor/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
from src.symbols.id_ import ref
from src.symbols.type_ import Type

__all__ = ("Translator",)
__all__ = (
"LabelledData",
"Translator",
)

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

Expand Down
6 changes: 3 additions & 3 deletions src/arch/z80/visitor/var_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ def visit_ARRAYDECL(self, node):

lbound_label = entry.mangled + ".__LBOUND__"
ubound_label = entry.mangled + ".__UBOUND__"

is_zero_based_array = all(bound.lower == 0 for bound in node.bounds)
bound_ptrs = ["0", "0"] # NULL by default
if entry.lbound_used or not is_zero_based_array:

if not entry.is_zero_based and entry.is_dynamically_accessed:
bound_ptrs[0] = lbound_label

if entry.ubound_used or OPTIONS.array_check:
bound_ptrs[1] = ubound_label

Expand Down
9 changes: 6 additions & 3 deletions src/lib/arch/zx48k/runtime/array/arrayalloc.asm
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ __ALLOC_LOCAL_ARRAY:
; ---------------------------------------------------------------------
; __ALLOC_INITIALIZED_LOCAL_ARRAY
; Allocates an array element area in the heap, and clears it filling it
; with 0 bytes
; with data whose pointer (PTR) is in the stack
;
; Parameters
; HL = Offset to be added to IX => HL = IX + HL
Expand Down Expand Up @@ -99,12 +99,15 @@ __ALLOC_LOCAL_ARRAY_WITH_BOUNDS2:
ld (hl), e
inc hl
ld (hl), d
pop de
pop de ;; PTR to ubound table
push bc ;; puts ret address back
ld a, d
or e
ret z ;; if PTR for UBound is 0, it's not used
inc hl
ld (hl), e
inc hl
ld (hl), d
push bc
ret


Expand Down
4 changes: 4 additions & 0 deletions src/lib/arch/zx48k/runtime/bound.asm
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ __CONT:
ld h, (hl)
ld l, a ; LD HL, (HL) => Origin of L/U Bound table

; for LBound only, HL = 0x0000 (NULL) if the array is all 0-based
or h
ret z ; Should never happen for UBound

add hl, de ; hl += OFFSET __LBOUND._xxxx
ld e, (hl) ; de = (hl)
inc hl
Expand Down
9 changes: 6 additions & 3 deletions src/lib/arch/zxnext/runtime/array/arrayalloc.asm
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ __ALLOC_LOCAL_ARRAY:
; ---------------------------------------------------------------------
; __ALLOC_INITIALIZED_LOCAL_ARRAY
; Allocates an array element area in the heap, and clears it filling it
; with 0 bytes
; with data whose pointer (PTR) is in the stack
;
; Parameters
; HL = Offset to be added to IX => HL = IX + HL
Expand Down Expand Up @@ -99,12 +99,15 @@ __ALLOC_LOCAL_ARRAY_WITH_BOUNDS2:
ld (hl), e
inc hl
ld (hl), d
pop de
pop de ;; PTR to ubound table
push bc ;; puts ret address back
ld a, d
or e
ret z ;; if PTR for UBound is 0, it's not used
inc hl
ld (hl), e
inc hl
ld (hl), d
push bc
ret


Expand Down
7 changes: 7 additions & 0 deletions src/symbols/arrayaccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class SymbolARRAYACCESS(SymbolCALL):
def __init__(self, entry, arglist: SymbolARGLIST, lineno: int, filename: str):
super().__init__(entry, arglist, lineno, filename)
assert all(gl.BOUND_TYPE == x.type_.type_ for x in arglist), "Invalid type for array index"
self.entry.ref.is_dynamically_accessed = True

@property
def entry(self):
Expand Down Expand Up @@ -90,6 +91,12 @@ def offset(self) -> int | None:
offset *= self.type_.size
return offset

@cached_property
def is_constant(self) -> bool:
"""Whether this array access is constant.
e.g. A(1) is constant. A(i) is not."""
return self.offset is None

@classmethod
def make_node(cls, id_: str, arglist: SymbolARGLIST, lineno: int, filename: str) -> Optional["SymbolARRAYACCESS"]:
"""Creates an array access. A(x1, x2, ..., xn)"""
Expand Down
4 changes: 0 additions & 4 deletions src/symbols/id_/_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ class SymbolID(SymbolIdABC):
"declared",
"filename",
"has_address",
"lineno",
"mangled",
"name",
"original_name",
"scope",
"scope_ref",
)

Expand Down
2 changes: 1 addition & 1 deletion src/symbols/id_/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


class SymbolIdABC(Symbol, ABC):
__slots__ = ()
__slots__ = "lineno", "mangled", "name", "scope"

scope: SCOPE
name: str
Expand Down
21 changes: 17 additions & 4 deletions src/symbols/id_/ref/arrayref.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class ArrayRef(VarRef):
__slots__ = "lbound_used", "ubound_used"
__slots__ = "is_dynamically_accessed", "lbound_used", "ubound_used"

def __init__(self, parent: SymbolID, bounds: SymbolBOUNDLIST):
super().__init__(parent)
Expand All @@ -19,6 +19,7 @@ def __init__(self, parent: SymbolID, bounds: SymbolBOUNDLIST):
self.callable = True
self.offset: str | None = None
self.byref = False # Whether this array is passed by ref to a func
self.is_dynamically_accessed: bool = False # Whether the array is accessed using variables at any moment

@property
def token(self) -> str:
Expand All @@ -39,8 +40,16 @@ def size(self):

@property
def memsize(self):
"""Total array cell + indexes size"""
return (2 + (2 if self.lbound_used or self.ubound_used else 0)) * TYPE.size(gl.PTR_TYPE)
"""Total array cell + indexes size
The current implementation of an array is a struct with the following information:

- PTR to DIM sizes table
- PTR to Array DATA region
- PTR to LBound Tables (always required; 0 for 0 based arrays)
- PTR to UBound Tables (always required, even if not used)
"""
ptr_size = TYPE.size(gl.PTR_TYPE) # Size of a pointer for the selected arch
return ptr_size * (3 + self.ubound_used)

@property
def data_label(self) -> str:
Expand All @@ -62,10 +71,14 @@ def t(self):
return "$" + self._t # Local string variables (and parameters) use '$' (see backend)

@property
def bounds(self):
def bounds(self) -> SymbolBOUNDLIST:
return self.parent.children[0]

@bounds.setter
def bounds(self, value: SymbolBOUNDLIST):
assert isinstance(value, SymbolBOUNDLIST)
self.parent.children = [value]

@property
def is_zero_based(self) -> bool:
return all(bound.lower == 0 for bound in self.bounds)
Loading