Browse Source

docs: save future-work analysis notes

Eric Streit 3 ngày trước cách đây
mục cha
commit
24b2a0247e
2 tập tin đã thay đổi với 320 bổ sung và 0 xóa
  1. 6 0
      docs/INDEX.md
  2. 314 0
      docs/future-work-2026-10-25.md

+ 6 - 0
docs/INDEX.md

@@ -32,6 +32,12 @@ bisecting *why* a decision was made, not for reading end-to-end).
 - **`gaps/README.md`** — minimal reproducers, one per unsupported gap,
   and the gm2-extension policy.
 
+## Future-work analysis
+
+- **`future-work-2026-10-25.md`** — TBITSIZE, ADDRESS arithmetic, set
+  ordering, PIM vs ISO coroutines, external assembly, dynamic-set design
+  and suggested order.
+
 ## Designs / running records
 
 - `analysis_generics.md` — generics (chosen ISO 10514-2 form, mechanism,

+ 314 - 0
docs/future-work-2026-10-25.md

@@ -0,0 +1,314 @@
+# Future-work analysis — 2026-10-25
+
+This note records the design discussions from 2026-10-25 so the
+questions do not have to be re-derived later.  It is not a commitment
+to implement everything.
+
+**State at the time of writing:** suite 310/310, one-shot fixpoint OK
+(3,845,439 bytes), per-object fixpoint OK (11 objects), corpus
+521/612 compile-OK, 0 crashes, 64 `LANG` and 27 `LIB`.
+
+---
+
+## 1. `TBITSIZE`
+
+`TBITSIZE` is a GNU Modula-2 `SYSTEM` procedure function:
+
+```modula2
+PROCEDURE TBITSIZE (<type>) : CARDINAL;
+```
+
+It returns the **minimum number of bits needed to represent a type**,
+not its normal storage size in bytes.  It is mainly useful for packed
+records/bitfields.  A `BOOLEAN` may be one bit logically but occupy a
+word in an unpacked record.
+
+- GNU Modula-2 supports it (and uses it in `M2WIDESET`).
+- V3 does not support it.
+- V3's existing `SIZE`/`TSIZE` report storage size in bytes.
+- Adding it would need:
+  - a type/variable argument form in the grammar;
+  - a descriptor query for minimum bit width (integer/real/char/enum/
+    subrange/record/packed-record cases);
+  - constant folding so `TBITSIZE(BYTE) = 8` works in `CONST`;
+  - interaction with packed record layout.
+
+It is a small-to-medium language gap, not a runtime feature.
+
+---
+
+## 2. `ADDRESS` arithmetic
+
+ISO `SYSTEM` defines:
+
+```modula2
+PROCEDURE ADDADR (addr: ADDRESS; offset: CARDINAL): ADDRESS;
+PROCEDURE SUBADR (addr: ADDRESS; offset: CARDINAL): ADDRESS;
+PROCEDURE DIFADR (addr1, addr2: ADDRESS): INTEGER;
+PROCEDURE MAKEADR (high: <type>; ...): ADDRESS;
+```
+
+V3 currently supports:
+
+- `ADR`
+- `ADDRESS`/pointer assignment
+- `ADDRESS`/pointer equality
+- `VAL`/`CAST` for compatible scalar representations
+
+V3 does **not** support:
+
+- `ADDADR`/`SUBADR`/`DIFADR`/`MAKEADR`
+- `ADDRESS + offset`, `ADDRESS - offset`, `ADDRESS - ADDRESS`
+- C-style arithmetic on typed `POINTER TO` values
+
+### Why it is missing
+
+`ADDRESS` is an opaque pointer-like value in V3's type system.  Raw
+pointer arithmetic is not part of the PIM/ISO base language and would
+weaken V3's separation between typed pointers and addresses.
+
+### Recommended implementation
+
+Add the ISO SYSTEM functions first, not general pointer arithmetic:
+
+- byte-addressed `ADDADR`/`SUBADR`;
+- `DIFADR` returning the byte difference (range-checked for `INTEGER`);
+- optional `MAKEADR`;
+- tests for offsets, null addresses, overflow and pointer/address
+  equality.
+
+For external C/assembly interaction, a C helper remains the pragmatic
+escape hatch.
+
+---
+
+## 3. Set ordering
+
+PIM/ISO set operations are:
+
+- equality `=`, inequality `#`, membership `IN`;
+- union `+`, difference `-`, intersection `*`, symmetric difference `/`.
+
+There is **no standard `<`, `<=`, `>`, `>=` ordering for sets**.  GNU
+Modula-2 adds inclusion ordering:
+
+```modula2
+a <= b   (* a is a subset of b *)
+a <  b   (* a is a proper subset of b *)
+a >= b   (* a is a superset of b *)
+a >  b   (* a is a proper superset of b *)
+```
+
+V3 currently rejects these; corpus case `largeset5` remains a `LANG`
+failure.
+
+### If implemented as a gm2-compatibility extension
+
+Fixed/inline sets:
+
+```text
+a <= b   iff   (a AND NOT b) == 0 for every word
+a <  b   iff   a <= b AND a # b
+```
+
+Dynamic sorted-range sets:
+
+```text
+a <= b   iff every range of a is covered by a range of b
+a <  b   iff a <= b AND a # b
+```
+
+Compiler work:
+
+- `SymTab.RelCheck`/`OrdCheck`: accept set ordering;
+- `Lower`: branch fixed/dynamic set ordering;
+- `QbeGen`: subset/superset comparisons;
+- tests: empty sets, equal sets, subset, proper subset, superset,
+  disjoint sets, mixed widths;
+- `largeset5` would likely move from `LANG` to compile-OK.
+
+This is a safe gm2 compatibility extension, not standard PIM/ISO.
+
+---
+
+## 4. PIM versus ISO coroutines
+
+### PIM
+
+Low-level SYSTEM primitives:
+
+```modula2
+TYPE PROCESS;
+PROCEDURE NEWPROCESS (body: PROC; workspace: ADDRESS;
+                      size: CARDINAL; VAR p: PROCESS);
+PROCEDURE TRANSFER (VAR from: PROCESS; to: PROCESS);
+PROCEDURE IOTRANSFER (VAR from, to: PROCESS;
+                      interruptNo: CARDINAL);
+```
+
+- caller supplies workspace;
+- caller explicitly transfers;
+- no scheduler;
+- no coroutine identity query;
+- no attach/detach/protection model;
+- `IOTRANSFER` uses an explicit interrupt number.
+
+V3 implements this with `ucontext`; `IOTRANSFER` currently degrades to a
+normal transfer because there is no interrupt subsystem.
+
+### ISO 10514-1 `COROUTINES`
+
+```modula2
+DEFINITION MODULE COROUTINES;
+
+TYPE
+  COROUTINE;
+  INTERRUPTSOURCE = CARDINAL;
+  PROTECTION = [UnassignedPriority .. 7];
+
+PROCEDURE NEWCOROUTINE (procBody: PROC; workspace: ADDRESS;
+                        size: CARDINAL; VAR cr: COROUTINE;
+                        [initProtection: PROTECTION]);
+PROCEDURE TRANSFER (VAR from: COROUTINE; to: COROUTINE);
+PROCEDURE IOTRANSFER (VAR from: COROUTINE; to: COROUTINE);
+PROCEDURE ATTACH (source: INTERRUPTSOURCE);
+PROCEDURE DETACH (source: INTERRUPTSOURCE);
+PROCEDURE IsATTACHED (source: INTERRUPTSOURCE): BOOLEAN;
+PROCEDURE HANDLER (source: INTERRUPTSOURCE): COROUTINE;
+PROCEDURE CURRENT (): COROUTINE;
+PROCEDURE LISTEN (p: PROTECTION);
+PROCEDURE PROT (): PROTECTION;
+PROCEDURE TurnInterrupts (to: PROTECTION): PROTECTION;
+PROCEDURE ListenLoop;
+END COROUTINES.
+```
+
+Main differences:
+
+| Area | PIM | ISO |
+| --- | --- | --- |
+| Context type | `PROCESS` | `COROUTINE` |
+| Creation | `NEWPROCESS` | `NEWCOROUTINE` + optional protection |
+| Switch | `TRANSFER` | `TRANSFER` |
+| Interrupt transfer | `IOTRANSFER(..., interruptNo)` | `IOTRANSFER(from,to)` with attached source |
+| Current context | none | `CURRENT` |
+| Interrupt registration | none | `ATTACH`/`DETACH`/`IsATTACHED`/`HANDLER` |
+| Protection/priority | none | `PROTECTION`, `LISTEN`, `PROT`, `TurnInterrupts` |
+| Event loop | user-written | `ListenLoop` |
+
+V3 has PIM coroutines but no ISO `COROUTINES` module.  A pure
+coroutine subset (`NEWCOROUTINE`, `TRANSFER`, `CURRENT`, workspace
+management) could map onto the existing ucontext layer.  The real
+interrupt/protection parts need an OS signal/event layer.
+
+---
+
+## 5. External assembly instead of inline `ASM`
+
+External assembly works today through `EXTERNAL` and the normal linker;
+no compiler support for inline `ASM` is required.
+
+```modula2
+DEFINITION MODULE AsmOps;
+PROCEDURE Add (a, b : CARDINAL) : CARDINAL;
+END AsmOps.
+```
+
+```modula2
+IMPLEMENTATION MODULE AsmOps;
+PROCEDURE Add (a, b : CARDINAL) : CARDINAL;
+  EXTERNAL;
+END AsmOps.
+```
+
+```asm
+    .text
+    .globl Add
+    .type Add,@function
+Add:
+    movl %edi, %eax
+    addl %esi, %eax
+    ret
+```
+
+```sh
+cc -c asm_add.s -o asm_add.o
+M2 -c AsmOps.def AsmOps.mod
+qbe -o AsmOps.s AsmOps.ssa
+cc -c AsmOps.s -o AsmOps.o
+cc Prog.o AsmOps.o asm_add.o runtime/syslib/shim.c -o Prog -lm
+```
+
+For `M2make --separate`, add the assembly object with `--extra
+asm_add.o` or link manually.
+
+### ABI notes
+
+- QBE target is `amd64_sysv`.
+- `INTEGER`/`CARDINAL` are 32-bit; `LONGINT` is 64-bit.
+- pointers are 64-bit `l` values.
+- `VAR` parameters receive addresses.
+- external procedures get no V3 static-link argument.
+- open arrays, especially `ARRAY OF CHAR`, are passed as descriptor
+  addresses, not raw C arrays.
+- record/array value parameters are passed by address.
+- composite results use a hidden result pointer.
+
+For anything beyond scalar arguments, use a small C wrapper around the
+assembly routine so the V3-facing signature is C-compatible.
+
+This is the recommended route for low-level code; inline `ASM` is
+unnecessary.
+
+---
+
+## 6. Dynamic `SET OF CARDINAL` / `INTEGER` — chosen design
+
+V3 now uses a sorted linked list of disjoint inclusive ranges:
+
+```text
+set = pointer to
+  { lo : CARDINAL; hi : CARDINAL; next : pointer }
+```
+
+This was chosen over a full 2^32-bit bit-vector (512 MiB per set value)
+and over a linked list of individual bits (too much per-value overhead).
+The range-list representation is:
+
+- O(number of contiguous runs), not O(cardinality);
+- compact for dense ranges;
+- supports the full 32-bit base range;
+- `INTEGER` values map with `VAL(CARDINAL, x) XOR 0x80000000`.
+
+Implemented operations include empty/range literals, `INCL`/`EXCL`/`IN`,
+assignment, equality, union/intersection/difference and symmetric
+difference.  Bounded sets such as `SET OF [0..100000]` keep the inline
+bit-vector form.
+
+### Current limitations
+
+- dynamic `SET CONST` is rejected (loud `230`), because no static
+  range-list layout exists yet;
+- record/array assignment containing dynamic sets currently copies the
+  pointer rather than deeply copying the range list;
+- nodes use `malloc`; assignment frees old lists but there is no GC or
+  program-exit cleanup;
+- `PACKEDSET` remains capped at 32 bits.
+
+Future work: runtime-initialised dynamic constants, deep composite
+copy, ownership/lifetime rules, and optionally a hash/paged bitset if
+range lists become too fragmented.
+
+---
+
+## 7. Suggested order of future work
+
+1. `TBITSIZE` (small, standard-facing).
+2. `ADDADR`/`SUBADR`/`DIFADR` (small, ISO SYSTEM).
+3. Set ordering (bounded gm2 compatibility; fixes `largeset5`).
+4. ISO `COROUTINES` subset, then interrupt/protection layer.
+5. Dynamic `SET CONST` and deep composite copies.
+6. Parser error recovery and diagnostics.
+
+External assembly needs no compiler work; document it as the supported
+low-level escape hatch.