Parcourir la source

lower L7: close the last single-file and session gaps for the flip

Six features plus the multi-file sessions now re-emit byte-identically
through Lower:

- Variant records: SymTab.LayoutRecord computes the layout at the
  record's END (the grammar called TypeSize before ComputeOffsets, so
  the size missed the variant region).  t_variant/t_variant2 match.
- Forward variables: the grammar marks a forward module-level reference
  in the designator (op=1); LowerDesign leaves an address instead of a
  dead load.  t_fwdvar matches.
- Bare zero-arg calls (Init, ClashA.Get) and typed-brace-free proc
  designators: the grammar now builds an NkCall for the implicit call,
  so Lower re-emits it.  DOpaqueProg/ClashProg match.
- Per-unit imports: Lower.NoteImportedProc records the exact proc entry
  for FROM M IMPORT P, so an unqualified call resolves to the imported
  proc rather than a same-named proc in another module.  Showcase11
  matches.

Result: all 94 single-file expect_run tests and all 47 sessions are
byte-identical under -lower; suite 204/204; FIXPOINT OK (3,554,237
bytes).
Eric Streit il y a 4 jours
Parent
commit
02bc5ae7c2
6 fichiers modifiés avec 3448 ajouts et 3379 suppressions
  1. 1 0
      compiler/src/Lower.def
  2. 40 2
      compiler/src/Lower.mod
  3. 15 8
      compiler/src/M2.atg
  4. 3376 3369
      compiler/src/M2.lst
  5. 5 0
      compiler/src/SymTab.def
  6. 11 0
      compiler/src/SymTab.mod

+ 1 - 0
compiler/src/Lower.def

@@ -44,6 +44,7 @@ PROCEDURE NoteProc (name: ARRAY OF CHAR; uid: CARDINAL;
                     res: SymTab.TypeIndex; depth: CARDINAL; ext: BOOLEAN);
 PROCEDURE MarkProcExternal;
 PROCEDURE NoteCProc (name: ARRAY OF CHAR);
+PROCEDURE NoteImportedProc (name: ARRAY OF CHAR);
 PROCEDURE NoteProcNode (n: AST.Node);
 PROCEDURE SetProcRes (t: SymTab.TypeIndex);
 PROCEDURE NoteParam (name: ARRAY OF CHAR; t: SymTab.TypeIndex;

+ 40 - 2
compiler/src/Lower.mod

@@ -16,6 +16,7 @@ CONST
   MaxSym  = 8192;   (* whole-session: >4096 vars/consts/params *)
   MaxName = 63;
   MaxProc = 2048;   (* whole-session: the compiler declares >1200 procs *)
+  MaxImp  = 512;    (* per-unit imports *)
   MaxPar  = 32;
   HashSize = 16384; (* power of two > MaxSym, MaxProc: open addressing *)
 
@@ -41,6 +42,12 @@ VAR
      lookups over thousands of entries), so FindSym/FindProc hash. *)
   symHash  : ARRAY [0 .. HashSize - 1] OF INTEGER;
   procHash : ARRAY [0 .. HashSize - 1] OF INTEGER;
+  (* Per-unit imports (FROM M IMPORT P): the exact proc entry for a
+     name, so an unqualified call resolves to the imported proc even
+     when another module declares the same name.  Reset each unit. *)
+  impProc  : ARRAY [0 .. MaxImp - 1] OF INTEGER;
+  impName  : ARRAY [0 .. MaxImp * 64 - 1] OF CHAR;
+  nImps    : CARDINAL;
   (* Scoping: each symbol records the procedure that owns it (-1 =
      module level); FindSym searches the emitted procedure's chain
      innermost-first so common names (s, i, k) do not collide across
@@ -354,11 +361,22 @@ PROCEDURE ProcVisible (i: INTEGER): BOOLEAN;
     RETURN procParent[i] = -1
   END ProcVisible;
 
+PROCEDURE ImpNameEq (i: CARDINAL; name: ARRAY OF CHAR): BOOLEAN;
+  BEGIN
+    RETURN SpanEq(impName, i * 64, name)
+  END ImpNameEq;
+
 PROCEDURE FindProc (name: ARRAY OF CHAR): INTEGER;
 (* Scope-aware: a nested procedure (e.g. one of two `Sep`s) must resolve
-   to the one in the emitted procedure's chain, not the last duplicate. *)
+   to the one in the emitted procedure's chain, not the last duplicate.
+   The current unit's imports win over any same-named proc. *)
   VAR i: INTEGER; owner: INTEGER;
   BEGIN
+    i := 0;
+    WHILE i < VAL(INTEGER, nImps) DO
+      IF ImpNameEq(VAL(CARDINAL, i), name) THEN RETURN impProc[i] END;
+      INC(i)
+    END;
     i := HashGet(procHash, procName, name);
     IF (i >= 0) AND ProcVisible(i) THEN RETURN i END;
     owner := emitProc;
@@ -395,6 +413,21 @@ PROCEDURE FindProcByUid (uid: CARDINAL): INTEGER;
     RETURN -1
   END FindProcByUid;
 
+PROCEDURE NoteImportedProc (name: ARRAY OF CHAR);
+(* FROM M IMPORT P (a procedure): remember the exact proc entry so an
+   unqualified call resolves to the imported proc, not a same-named
+   proc declared in another module.  Reset at each unit. *)
+  VAR pi: INTEGER;
+  BEGIN
+    IF SymTab.SymKind(name) # SymTab.KindProc THEN RETURN END;
+    pi := FindProcByUid(SymTab.ProcUid(name));
+    IF pi < 0 THEN RETURN END;
+    IF nImps >= MaxImp THEN RETURN END;
+    impProc[nImps] := pi;
+    CopySpan(name, impName, 0, nImps * 64);
+    INC(nImps)
+  END NoteImportedProc;
+
 PROCEDURE Resolve (nm: ARRAY OF CHAR; VAR k: INTEGER;
                    VAR t: SymTab.TypeIndex): BOOLEAN;
   VAR kind: INTEGER; ti: SymTab.TypeIndex;
@@ -1135,7 +1168,11 @@ PROCEDURE LowerDesign (n: AST.Node; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
       END
     ELSIF (k = SymTab.KindVar) OR (k = SymTab.KindParam) THEN
       cls := SymTab.ClassOf(t);
-      IF (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
+      IF AST.Op(n) = 1 THEN
+        (* a forward module-level reference: the grammar's FwdAddrOper
+           leaves an address (sfx=TRUE), not a loaded value *)
+        QbeGen.AddrOf(nm, q); sfx := TRUE
+      ELSIF (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
          OR (cls = SymTab.ClChar) OR (cls = SymTab.ClUChar)
          OR (cls = SymTab.ClEnum) OR (cls = SymTab.ClReal) THEN
         QbeGen.LoadVar(nm, cls = SymTab.ClReal, q)
@@ -2616,6 +2653,7 @@ PROCEDURE BeginUnit;
 (* Snapshot the pre-parse state so Lower can discard the grammar's
    suppressed inline mutations for this unit. *)
   BEGIN
+    nImps := 0;
     QbeGen.SaveSession
   END BeginUnit;
 

+ 15 - 8
compiler/src/M2.atg

@@ -501,9 +501,12 @@ PRODUCTIONS
                                              IF NOT SymTab.DeclareCProc(n) THEN
                                                SemError(201) END;
                                              Lower.NoteCProc(n)
-                                           ELSIF SymTab.ModKnown(mod)
-                                             AND NOT SymTab.ImportFrom(mod, n) THEN
-                                             SemError(201) END; .)
+                                           ELSIF SymTab.ModKnown(mod) THEN
+                                             IF NOT SymTab.ImportFrom(mod, n) THEN
+                                               SemError(201)
+                                             ELSE Lower.NoteImportedProc(n)
+                                             END
+                                           END; .)
     | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
       | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
       | "UCHR" | "CHR8" | "UORD"
@@ -719,7 +722,7 @@ PRODUCTIONS
                                              tagOk: BOOLEAN; .)
     = "RECORD"                          (. t := SymTab.NewRecord(); .)
       [ RecItem<t> { ";" [ RecItem<t> ] } ]
-      "END" .
+      "END"                             (. SymTab.LayoutRecord(t); .) .
   RecItem<rec: SymTab.TypeIndex>        (. VAR tt: SymTab.TypeIndex; .)
     = RecField<rec>
     | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
@@ -2259,10 +2262,11 @@ PRODUCTIONS
                                              qb, cv: QbeGen.QVal;
                                              fid, fref, slot: INTEGER;
                                              r: BOOLEAN;
-                                              astDes, astSel: AST.Node; .)
+                                              astDes, astSel: AST.Node;
+                                             fwd: BOOLEAN; .)
     = GetIdent<n>                       (. methCls := SymTab.InvalidType;
                                            QbeGen.CopyOp(n, qn);
-                                           sfx := FALSE;
+                                           sfx := FALSE; fwd := FALSE;
                                            fid := 0; fref := 0; slot := 0;
                                            IF NOT SymTab.Lookup(n) THEN
                                              (* a bare method name inside
@@ -2291,7 +2295,7 @@ PRODUCTIONS
                                                FwdVarNote(fref, slot);
                                                fid := slot;
                                                QbeGen.FwdAddrOper(fid, q);
-                                               sfx := TRUE
+                                               sfx := TRUE; fwd := TRUE
                                              ELSE
                                                SemError(201);
                                                t :=
@@ -2429,7 +2433,8 @@ PRODUCTIONS
                                              END
                                            END; .)
       (. astDes := AST.MakeNode(AST.NkDesignator);
-         AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
+         AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n));
+         IF fwd THEN AST.SetOp(astDes, 1) END; .)
       { "[" Expr<it, iq>
                                         (. AST.SetChild(astDes, AST.NChild(astDes),
              AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
@@ -3280,6 +3285,8 @@ PRODUCTIONS
                                                  SymTab.ProcDepthOf(qn),
                                                  SymTab.IsExternal(qn));
                                                QbeGen.CallEnd(TRUE, q);
+                                               astCur := AST.MakeNode(AST.NkCall);
+                                               AST.SetChild(astCur, 0, astD);
                                                t := SymTab.ProcRes(qn)
                                              ELSE
                                                (* procedure used as a

Fichier diff supprimé car celui-ci est trop grand
+ 3376 - 3369
compiler/src/M2.lst


+ 5 - 0
compiler/src/SymTab.def

@@ -319,6 +319,11 @@ PROCEDURE EnterThisParam (cls: TypeIndex): BOOLEAN;
 PROCEDURE LayoutClass (t: TypeIndex);
 (* Computes a class's field offsets / size. *)
 
+PROCEDURE LayoutRecord (t: TypeIndex);
+(* Computes a record's field offsets / size now (idempotent).  Called at
+   the record's END so a variant record's size is settled before any
+   VAR of that type is emitted. *)
+
 PROCEDURE ParentOf (t: TypeIndex): TypeIndex;
 (* The single parent class of t (InvalidType when none). *)
 

+ 11 - 0
compiler/src/SymTab.mod

@@ -1526,6 +1526,17 @@ PROCEDURE LayoutClass (t: TypeIndex);
     END
   END LayoutClass;
 
+PROCEDURE LayoutRecord (t: TypeIndex);
+(* Computes a record's field offsets / size now (idempotent). *)
+  VAR r: TypeIndex;
+  BEGIN
+    r := Resolve(t);
+    IF (r # InvalidType) AND (tform[r] = FRecord)
+       AND NOT tdone[r] THEN
+      ComputeOffsets(r)
+    END
+  END LayoutRecord;
+
 PROCEDURE FieldOffset (rec: TypeIndex; name: ARRAY OF CHAR): INTEGER;
   VAR r: TypeIndex;
     f: FieldPtr;

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff