Просмотр исходного кода

language: add open-array ABI helpers (M1)

Add SymTab ArrayRank, IsMultiArray, ArrayLeafBytes, ArrayStride and ArrayPayloadSize for the planned per-level view ABI. Raise MaxDefer from 256 to 512 (the compiler now declares 257 procedures) and the session SSA buffer from 4 to 8 MiB so self-hosting can still build. No array layout/codegen change yet. Gates: suite 283/283, fixpoint OK 4,198,600 bytes, corpus 512/612 compile-OK.
Eric Streit 2 дней назад
Родитель
Сommit
2cc67763b6

+ 1 - 1
README.md

@@ -48,7 +48,7 @@ docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 ## Status (2026-10-23)
 
 - Suite **283/283**; self-hosting **fixpoint OK** (byte-identical
-  stage2/stage3, 4,184,457 bytes); corpus **512/612 compile-OK,
+  stage2/stage3, 4,198,600 bytes); corpus **512/612 compile-OK,
   0 crashes** (`tools/v3-corpus`; the corpus is gm2's testsuite, so it
   mixes conforming Modula-2 with gm2 leniencies — see `docs/gaps/`).
   `lazyunique` now runs; the remaining `except*` corpus files still hit

+ 1 - 1
compiler/src/QbeGen.mod

@@ -72,7 +72,7 @@ VAR
   initNames : ARRAY [0 .. 31] OF QVal;
   nFini : CARDINAL;
   finiNames : ARRAY [0 .. 31] OF QVal;
-  sessBuf : ARRAY [0 .. 4194303] OF CHAR;  (* whole image, buffered (4 MiB:
+  sessBuf : ARRAY [0 .. 8388607] OF CHAR;  (* whole image, buffered (8 MiB:
                                               must hold the compiler's own
                                               image text when self-hosting) *)
   sessUsed : CARDINAL;

+ 13 - 0
compiler/src/SymTab.def

@@ -562,6 +562,19 @@ PROCEDURE ArrayLen (t: TypeIndex): CARDINAL;
 (* Static element count, 0 for open/invalid. *)
 PROCEDURE ArrayDepth (t: TypeIndex): CARDINAL;
 (* Nesting depth (open/fixed levels); 0 for non-arrays. *)
+PROCEDURE ArrayRank (t: TypeIndex): CARDINAL;
+(* Alias for ArrayDepth, named for the open-array ABI. *)
+PROCEDURE IsMultiArray (t: TypeIndex): BOOLEAN;
+(* TRUE when the array rank is greater than one. *)
+PROCEDURE ArrayLeafBytes (t: TypeIndex): CARDINAL;
+(* Payload bytes of the scalar/record leaf element of an array; 0 for
+   non-arrays or invalid types. *)
+PROCEDURE ArrayStride (t: TypeIndex; level: CARDINAL): CARDINAL;
+(* Bytes between adjacent elements at a 0-based array level for a fixed
+   array; 0 when the level is invalid or a lower count is open/unknown. *)
+PROCEDURE ArrayPayloadSize (t: TypeIndex): CARDINAL;
+(* Static payload bytes of a fully fixed array (header excluded); 0 for
+   open/invalid/non-array types. *)
 
 PROCEDURE TypeSize (t: TypeIndex): CARDINAL;
 (* Inline footprint in bytes: scalars 4/8, sets words*4, pointers,

+ 76 - 3
compiler/src/SymTab.mod

@@ -11,6 +11,7 @@ CONST
   ResDepth  = 64;
   MaxPP     = 1024;   (* total procedure-type parameter slots *)
   MaxEnumLit = 8192;  (* enumeration literals, for export/import *)
+  MaxDefer  = 512;    (* deferred procedure bodies (two-phase parse) *)
 
   (* descriptor forms *)
   FNone = 0; FAlias = 1; FSub = 2; FEnum = 3; FArray = 4;
@@ -105,9 +106,9 @@ VAR
      scope, saved while still current, restored for the re-parse pass *)
   uidBase : ARRAY [0 .. 1023] OF Name;  (* uid -> base name (mangling) *)
   nDefer : CARDINAL;
-  deferProc : ARRAY [0 .. 255] OF SymPtr;
-  deferScope : ARRAY [0 .. 255] OF ScopePtr;
-  deferSeq : ARRAY [0 .. 255] OF CARDINAL;
+  deferProc : ARRAY [0 .. MaxDefer - 1] OF SymPtr;
+  deferScope : ARRAY [0 .. MaxDefer - 1] OF ScopePtr;
+  deferSeq : ARRAY [0 .. MaxDefer - 1] OF CARDINAL;
   declSeq : CARDINAL;     (* next declaration-order number *)
   orderCheck : BOOLEAN;   (* enforce use-before-decl in a deferred body *)
   orderSeq : CARDINAL;    (* the enclosing procedure's declaration seq *)
@@ -1583,6 +1584,78 @@ PROCEDURE ElemBytes (t: TypeIndex): CARDINAL;
 PROCEDURE IsCharArray (t: TypeIndex): BOOLEAN;
   BEGIN RETURN ClassOf(ArrayElem(t)) = ClChar END IsCharArray;
 
+PROCEDURE ArrayRank (t: TypeIndex): CARDINAL;
+  BEGIN
+    RETURN ArrayDepth(t)
+  END ArrayRank;
+
+PROCEDURE IsMultiArray (t: TypeIndex): BOOLEAN;
+  BEGIN
+    RETURN ArrayDepth(t) > 1
+  END IsMultiArray;
+
+PROCEDURE ArrayLeafBytes (t: TypeIndex): CARDINAL;
+(* Walk to the scalar/record at the bottom of the array chain. *)
+  VAR cur: TypeIndex; cls: INTEGER;
+  BEGIN
+    cur := Resolve(t);
+    IF (cur = InvalidType) OR (tform[cur] # FArray)
+       AND (tform[cur] # FOpenArr) THEN
+      RETURN 0
+    END;
+    WHILE (cur # InvalidType)
+       AND ((tform[cur] = FArray) OR (tform[cur] = FOpenArr)) DO
+      cur := Resolve(ArrayElem(cur))
+    END;
+    IF cur = InvalidType THEN RETURN 0 END;
+    cls := ClassOf(cur);
+    IF (cls = ClChar) OR (cls = ClByte) OR (cls = ClSByte) THEN RETURN 1
+    ELSIF (cls = ClWord16) OR (cls = ClSWord16) THEN RETURN 2
+    ELSIF (cls = ClRecord) OR (cls = ClClass) OR (cls = ClSet) THEN
+      RETURN TypeSize(cur)
+    ELSIF (cls = ClReal) OR (cls = ClLong) OR (cls = ClPtr)
+       OR (cls = ClProc) OR (cls = ClStr) THEN RETURN 8
+    ELSIF cls = ClInvalid THEN RETURN 0
+    ELSE RETURN 4
+    END
+  END ArrayLeafBytes;
+
+PROCEDURE ArrayStride (t: TypeIndex; level: CARDINAL): CARDINAL;
+  VAR r, cur: TypeIndex; rank, k, len, stride: CARDINAL;
+  BEGIN
+    rank := ArrayDepth(t);
+    IF (rank = 0) OR (level >= rank) THEN RETURN 0 END;
+    stride := ArrayLeafBytes(t);
+    IF stride = 0 THEN RETURN 0 END;
+    r := Resolve(t);
+    cur := r;
+    k := 0;
+    WHILE k < rank DO
+      IF k > level THEN
+        IF (cur = InvalidType) OR (tform[cur] = FOpenArr) THEN RETURN 0 END;
+        len := ArrayLen(cur);
+        IF len = 0 THEN RETURN 0 END;
+        stride := stride * len
+      END;
+      cur := Resolve(ArrayElem(cur));
+      INC(k)
+    END;
+    RETURN stride
+  END ArrayStride;
+
+PROCEDURE ArrayPayloadSize (t: TypeIndex): CARDINAL;
+  VAR r: TypeIndex; stride, count: CARDINAL;
+  BEGIN
+    r := Resolve(t);
+    IF (r = InvalidType) OR (tform[r] = FOpenArr) THEN RETURN 0 END;
+    IF (tform[r] # FArray) THEN RETURN 0 END;
+    stride := ArrayStride(t, 0);
+    IF stride = 0 THEN RETURN 0 END;
+    count := ArrayLen(r);
+    IF count = 0 THEN RETURN 0 END;
+    RETURN stride * count
+  END ArrayPayloadSize;
+
 PROCEDURE ArrObjSize (t: TypeIndex): CARDINAL;
 (* full inline size of a fixed array: header (count) + packed elements
    (+1 terminator byte for CHAR arrays) *)

+ 2 - 1
docs/INDEX.md

@@ -45,7 +45,8 @@ bisecting *why* a decision was made, not for reading end-to-end).
 - **`design-open-arrays.md`** — multi-dimensional open-array ABI:
   per-level view descriptors over a flat backing block, payload
   `SIZE`/`ADR`, fixed/open 2-D and 3-D arrays, row/byte flattening,
-  records/constructors and corpus mapping.  Design only.
+  records/constructors and corpus mapping.  Design; M1 type/ABI
+  helpers are implemented.
 - `blaise-phases-map.md`, `language-report.md`, `grammar.md` — the
   grammar/phases reference.
 - `summary_l3_selfhost_fix.md` — the self-host root cause; also where

+ 1 - 1
docs/STATUS.md

@@ -6,7 +6,7 @@ This answers "where are we now?".
 
 - Suite **283/283** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
-  byte-identical (4,184,457 bytes).
+  byte-identical (4,198,600 bytes).
 - Corpus **512 / 612** sources compile with 0 errors, **0 crashes**
   (`tools/v3-corpus/corpus.sh` over the gm2 testsuite; the harness now
   resolves V3's own shipped libraries); the rest are genuine language

+ 1 - 1
docs/comparison-PIM4-gm2-V3.md

@@ -1,7 +1,7 @@
 # PIM4 vs GNU Modula-2 vs M2R10 vs TopSpeed V3 vs V3 — feature comparison
 
 **Date:** 2026-10-23 · **V3 state:** `v3-finally` (suite
-283/283, self-hosting fixpoint OK 4,184,457 bytes, corpus 512/612,
+283/283, self-hosting fixpoint OK 4,198,600 bytes, corpus 512/612,
 0 crashes).
 
 **Scope and sources.**

+ 17 - 8
docs/design-open-arrays.md

@@ -1,7 +1,9 @@
 # Design — multi-dimensional open arrays
 
-**Status: design only (2026-10-23).**  Nothing in this document is
-implemented yet.  Baseline: suite **283/283**, fixpoint OK **4,184,457
+**Status: design + M1 type/ABI helpers (2026-10-23).**  The view
+descriptor ABI is designed but no array layout/codegen change is
+implemented yet.  `SymTab` now exposes the rank/payload/stride queries
+needed by M2.  Baseline: suite **283/283**, fixpoint OK **4,198,600
 bytes**, corpus **512/612 compile-OK**, 0 crashes.
 
 Interactive decisions already taken:
@@ -251,16 +253,19 @@ This is an open question to confirm against ISO.
 
 ## 4. Type system changes
 
-Add queries in `SymTab`:
+Add queries in `SymTab` (implemented in M1):
 
 ```text
-ArrayRank        (t) : CARDINAL
+ArrayRank        (t) : CARDINAL       (* ArrayDepth under an ABI name *)
 IsMultiArray     (t) : BOOLEAN
+ArrayLeafBytes   (t) : CARDINAL       (* scalar/record leaf bytes *)
 ArrayStride      (t, level) : CARDINAL
-ArrayPayloadSize (t) : CARDINAL
-ArrayViewType    (t) : TypeIndex / representation marker
+ArrayPayloadSize (t) : CARDINAL       (* only fully fixed arrays *)
 ```
 
+`ArrayStride`/`ArrayPayloadSize` return 0 for open/unknown counts; M3
+will use the runtime view metadata for those cases.
+
 Compatibility rules:
 
 - same-rank fixed/open arrays remain compatible by element type and
@@ -358,8 +363,12 @@ Gates after each step: suite, fixpoint, corpus.
 
 ## 7. Milestones
 
-1. **M1 — type/ABI helpers** (design + `ArrayRank`/payload/stride
-   queries; no codegen change).
+1. **M1 — type/ABI helpers** — **done (2026-10-23)**
+   - `ArrayRank`, `IsMultiArray`, `ArrayLeafBytes`, `ArrayStride`,
+     `ArrayPayloadSize` in `SymTab`.
+   - `MaxDefer` raised from 256 to 512 (the compiler now declares 257
+     procedures) and the session SSA buffer raised from 4 to 8 MiB.
+   - No array layout/codegen change.
 2. **M2 — fixed multi storage** (flat payload + static/local views;
    keep 1-D unchanged).
 3. **M3 — open view descriptors** (stack views, calls, row subviews,

+ 9 - 4
docs/handoff-2026-10-23-next.md

@@ -1,7 +1,7 @@
 # Next session — plan (from 2026-10-23)
 
 **Branch:** `master`.  **Feature state:** `v3-exceptions` + `v3-ptrchain` + `v3-function-exception` + `v3-finally`.
-**Gates:** suite **283/283**, fixpoint **OK (4,184,457 bytes)**,
+**Gates:** suite **283/283**, fixpoint **OK (4,198,600 bytes)**,
 corpus **512/612, 0 crashes**.
 
 Read first: `docs/STATUS.md`, `docs/features.md`,
@@ -78,11 +78,16 @@ descriptors over one contiguous flat backing block**, with payload
 2-D and 3-D, `VAR`, subarray views, row → 1-D, 2-D → `ARRAY OF BYTE`,
 records/constructors.
 
+**M1 — type/ABI helpers — done (2026-10-23).**  `ArrayRank`,
+`IsMultiArray`, `ArrayLeafBytes`, `ArrayStride`, `ArrayPayloadSize`;
+`MaxDefer` 512 and the session SSA buffer 8 MiB.  No layout/codegen
+change yet.  Next is M2: fixed multi-dimensional storage.
+
 Corpus: `unbounded`, `unbounded2/3/4/6/8`, `array9`, `adrunbounded3`.
 Do not just accept the files; the ABI and `ADR(m) = ADR(m[0])` checks
-must be real.  `unbounded5` remains a declaration-order case.  Next
-step is design M1: type/ABI helpers and fixed-multi layout, then open
-views and calls.
+must be real.  `unbounded5` remains a declaration-order case.  Next is
+M2: fixed multi-dimensional flat storage, then the open views/call
+conversion in M3.
 
 ## 4. Runtime range checks — done, follow-ups