瀏覽代碼

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 天之前
父節點
當前提交
018bf0c7c1
共有 3 個文件被更改,包括 41 次插入 和 12 次删除
  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:
 1. **A string VALUE parameter** — the current rung:
    `procedure Center(S : AnyString)` (`CALC.INC:17`).  `ProcFunc` refuses a
    `procedure Center(S : AnyString)` (`CALC.INC:17`).  `ProcFunc` refuses a
    parameter wider than a word; a `string[n]` parameter is `n+1` bytes.  TP3
    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
 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
    `type`/`const`/`var` inside a nested function (`CALC.INC:767-778`, the
    enum-indexed array of strings), `Succ`/`Pred`/`Ord`/`Chr`.
    enum-indexed array of strings), `Succ`/`Pred`/`Ord`/`Chr`.

+ 25 - 6
shell/Compiler.mod

@@ -4608,6 +4608,19 @@ BEGIN
    END
    END
 END SymEpi ;
 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 ProcFunc () ;
 (* PROCEDURE name (params) ; body | FUNCTION name (params) : type ; body *)
 (* PROCEDURE name (params) ; body | FUNCTION name (params) : type ; body *)
 VAR nm : ARRAY [0..MaxName] OF CHAR ;
 VAR nm : ARRAY [0..MaxName] OF CHAR ;
@@ -4688,7 +4701,7 @@ BEGIN
                symtab [i].cls := cls ; symtab [i].size := size ;
                symtab [i].cls := cls ; symtab [i].size := size ;
                symtab [i].elem := elem ;
                symtab [i].elem := elem ;
                symtab [i].off := parmOff ;
                symtab [i].off := parmOff ;
-               parmOff := parmOff + 2 ;
+               parmOff := parmOff + SlotSize (cls, size) ;
                INC (i)
                INC (i)
             END ;
             END ;
             IF MatchDelim (')') THEN
             IF MatchDelim (')') THEN
@@ -4716,10 +4729,15 @@ BEGIN
       from BP, which has to be the FIRST declared parameter's slot.
       from BP, which has to be the FIRST declared parameter's slot.
 
 
       During the loop the offsets were provisional, in declaration order
       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
       The range is exactly the parameters: the only symbol created while the
       list is read is the parameter itself (NewSym inside the loop),
       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. *)
       nestMark, and a function's result variable is created after this point. *)
    i := nestMark ;
    i := nestMark ;
    WHILE i < symTop DO
    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)
       INC (i)
    END ;
    END ;
    IF isFunc THEN
    IF isFunc THEN

+ 2 - 1
shell/tests/nonvacuity.sh

@@ -952,7 +952,8 @@ p = 'Compiler.mod'
 s = open(p).read()
 s = open(p).read()
 old = """   i := nestMark ;
 old = """   i := nestMark ;
    WHILE i < symTop DO
    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)
       INC (i)
    END ;
    END ;
 """
 """