Browse Source

compiler: generalise parameter SLOTS (prerequisite for string value params)

Step 1 of the string-value-parameter work, deliberately behaviour-preserving:
every accepted parameter is still a scalar with a 2-byte slot, so nothing
observable moves (matrix 67/67, ladder unchanged at ERR 102 10350, framedisp
PASS, 56/56 executed under qemu and Exec86).

  - SlotSize (cls, size): TP3's tstscal (TPSRC7 1243) - a scalar-like parameter
    occupies AT LEAST two bytes on the stack even when its type is one byte;
    anything larger spends its own size.  A string[n] parameter is n+1 bytes.
  - parmOff advances by the slot size, and the callee's reverse layout is the
    general `off := 8 + frameTotal - off - slot`.  With every slot 2 that is
    exactly the old `parmOff + 2 - off`, so no existing frame moves; a larger
    slot (a string's 71 bytes) falls out of the same formula.
  - Strings are STILL refused (size > 2 -> ENoLib), so the caller still pushes
    only 2-byte scalars; the next step makes the callee's parameter list
    visible at call sites and then pushes a string's whole slot.

nonvacuity.sh: the ProcFunc-remap mutation anchored on the old line; updated to
the new formula, and it still catches a callee laid out in declaration order
(t36).  86 ok / 0 failed.
Eric Streit 3 ngày trước cách đây
mục cha
commit
018bf0c7c1
3 tập tin đã thay đổi với 41 bổ sung và 12 xóa
  1. 14 5
      CALC-COMPILE.md
  2. 25 6
      shell/Compiler.mod
  3. 2 1
      shell/tests/nonvacuity.sh

+ 14 - 5
CALC-COMPILE.md

@@ -513,11 +513,20 @@ and green after, an execution proof where the image fits, and a commit.
 1. **A string VALUE parameter** — the current rung:
    `procedure Center(S : AnyString)` (`CALC.INC:17`).  `ProcFunc` refuses a
    parameter wider than a word; a `string[n]` parameter is `n+1` bytes.  TP3
-   passes a large value parameter how?  Check `TPSRC7`'s parameter machinery
-   (and `RESUME-TP3.md` §3.11, which covers `var` parameters: SEG then OFFSET).
-   The cheap first cut is a string parameter passed **by address with a copy
-   into a callee slot** the way TP3 does, or - if that is the wrong shape - a
-   loud `Err` and move on.  `var` parameters proper are item 4.
+   passes a value parameter's whole size on the stack (`TPSRC7` `tstscal`), so
+   the caller must copy the string into the callee's slot.
+   **Step 1 is DONE** (`v-TP3-CALC-PARAMSLOTS`): parameter *slots* are
+   generalised — `SlotSize (cls, size)` is TP3's "scalar-like ⇒ at least two
+   bytes, larger ⇒ its own size", and the callee's reverse layout is the
+   general `off := 8 + frameTotal − off − slot`, which reduces exactly to the
+   old `parmOff + 2 − off` while every slot is 2.  Nothing observable moved
+   (matrix 67/67, ladder unchanged, framedisp PASS, 56/56 executed).
+   **Next:** (2) store the parameter list on the procedure symbol so a call
+   site can size each argument; (3) push a string's whole slot (`SUB SP,size /
+   MOV DI,SP / MOV SI,src / MOV CX,size / CLD / REP MOVSB`, or a `TU_PushStr`
+   entry) and allow `size > 2` for string parameters; (4) a fixture where the
+   callee **mutates** `S` and the caller's variable is unchanged — the value
+   semantics TP3 promises.  `var` parameters proper are item 6.
 2. **The rest of the declaration part**, if the rung is still there: local
    `type`/`const`/`var` inside a nested function (`CALC.INC:767-778`, the
    enum-indexed array of strings), `Succ`/`Pred`/`Ord`/`Chr`.

+ 25 - 6
shell/Compiler.mod

@@ -4608,6 +4608,19 @@ BEGIN
    END
 END SymEpi ;
 
+PROCEDURE SlotSize (cls, size : CARDINAL) : CARDINAL ;
+(* How many bytes a value parameter occupies in the callee's stack frame.
+   TP3's `tstscal' (TPSRC7 1243): a scalar-like parameter is AT LEAST two
+   bytes on the stack even when its type is one byte; anything larger spends
+   its own size.  Generalised here so step 2 can put a string's 71 bytes on
+   the stack without changing what a scalar does today. *)
+BEGIN
+   IF (cls = TScalar) OR (cls = TChar) OR (cls = TBool) OR (cls = TEnum) THEN
+      RETURN 2
+   END ;
+   RETURN size
+END SlotSize ;
+
 PROCEDURE ProcFunc () ;
 (* PROCEDURE name (params) ; body | FUNCTION name (params) : type ; body *)
 VAR nm : ARRAY [0..MaxName] OF CHAR ;
@@ -4688,7 +4701,7 @@ BEGIN
                symtab [i].cls := cls ; symtab [i].size := size ;
                symtab [i].elem := elem ;
                symtab [i].off := parmOff ;
-               parmOff := parmOff + 2 ;
+               parmOff := parmOff + SlotSize (cls, size) ;
                INC (i)
             END ;
             IF MatchDelim (')') THEN
@@ -4716,10 +4729,15 @@ BEGIN
       from BP, which has to be the FIRST declared parameter's slot.
 
       During the loop the offsets were provisional, in declaration order
-      (parmOff starts at 4 and grows by 2 per parameter), so parameter k of n
-      sat at 4 + 2*(k-1).  The map `off := parmOff + 2 - off' sends that to
-      4 + 2*(n-k) - k = 1 to the far end, k = n to BP+4 - which is the layout
-      above, with no offset invented and none lost.
+      (parmOff starts at 4 and grows by each parameter's SLOT size), so
+      parameter k sat at 4 + sum of the slots before it.  For slot sizes s and
+      frame total T, the parameter's final base is
+      4 + (T - prefix - s) = 8 + T - off - s, which sends the FIRST declared
+      parameter to the far end and the LAST to BP+4.  With every slot 2 -
+      every scalar, which is all this compiler accepts today - that reduces
+      exactly to the old `parmOff + 2 - off`, so no existing frame moves.
+      A slot larger than 2 (a string's 71 bytes, once the caller can push it)
+      falls out of the same formula.
 
       The range is exactly the parameters: the only symbol created while the
       list is read is the parameter itself (NewSym inside the loop),
@@ -4727,7 +4745,8 @@ BEGIN
       nestMark, and a function's result variable is created after this point. *)
    i := nestMark ;
    WHILE i < symTop DO
-      symtab [i].off := parmOff + 2 - symtab [i].off ;
+      symtab [i].off := 8 + (parmOff - 4) - symtab [i].off
+                        - SlotSize (symtab [i].cls, symtab [i].size) ;
       INC (i)
    END ;
    IF isFunc THEN

+ 2 - 1
shell/tests/nonvacuity.sh

@@ -952,7 +952,8 @@ p = 'Compiler.mod'
 s = open(p).read()
 old = """   i := nestMark ;
    WHILE i < symTop DO
-      symtab [i].off := parmOff + 2 - symtab [i].off ;
+      symtab [i].off := 8 + (parmOff - 4) - symtab [i].off
+                        - SlotSize (symtab [i].cls, symtab [i].size) ;
       INC (i)
    END ;
 """