Procházet zdrojové kódy

merge: short-circuit AND/OR (deferred buffering + memory-slot merge); suite 111/111

Eric Streit před 2 týdny
rodič
revize
757e3925ed
4 změnil soubory, kde provedl 677 přidání a 524 odebrání
  1. 48 12
      compiler/src/M2.atg
  2. 548 512
      compiler/src/M2.lst
  3. 15 0
      compiler/src/QbeGen.def
  4. 66 0
      compiler/src/QbeGen.mod

+ 48 - 12
compiler/src/M2.atg

@@ -1721,7 +1721,9 @@ PRODUCTIONS
                                                QbeGen.QVal;
                                              neg, isR, isL, folded:
                                                BOOLEAN;
-                                             lw, rw, mw: CARDINAL; .)
+                                             lw, rw, mw: CARDINAL;
+                                             lTrue, lNext, lDone, qr, qs:
+                                               QbeGen.QVal; .)
     =                                   (. neg := FALSE; .)
       [ "+" | "-"                       (. neg := TRUE; .) ]
       Term<t, q>                        (. IF neg THEN
@@ -1734,16 +1736,32 @@ PRODUCTIONS
                                              QbeGen.CopyOp(qt, q)
                                            END
                                          END; .)
-      { AddOp<op> Term<t2, q2>
+      { AddOp<op>                       (. IF op = SymTab.OpOr THEN
+                                             QbeGen.DelayBegin END; .)
+        Term<t2, q2>                     (. IF op = SymTab.OpOr THEN
+                                             QbeGen.DelayEnd END; .)
         (. IF op = SymTab.OpOr THEN
+             (* short-circuit: if q is true the RHS is skipped *)
              IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
                t := SymTab.BoolType()
              ELSE SemError(212); t := SymTab.InvalidType END;
              IF t # SymTab.InvalidType THEN
-               QbeGen.NewTemp(qt);
-               QbeGen.Op3("or", qt, q, q2, FALSE);
-               QbeGen.CopyOp(qt, q)
-             ELSE QbeGen.CopyOp("0", q)
+               QbeGen.Slot4(qs);
+               QbeGen.NewLabel(lTrue);
+               QbeGen.NewLabel(lNext);
+               QbeGen.NewLabel(lDone);
+               QbeGen.Jnz(q, lTrue, lNext);
+               QbeGen.EmitLabel(lTrue);
+               QbeGen.StoreW(qs, "1");
+               QbeGen.Jmp(lDone);
+               QbeGen.EmitLabel(lNext);
+               QbeGen.DelayFlush;
+               QbeGen.StoreW(qs, q2);
+               QbeGen.Jmp(lDone);
+               QbeGen.EmitLabel(lDone);
+               QbeGen.LoadW(qs, qr);
+               QbeGen.CopyOp(qr, q)
+             ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
              END
            ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
  AND (SymTab.ClassOf(t) = SymTab.ClSet)
@@ -1815,17 +1833,35 @@ PRODUCTIONS
                                              q2, qt, wq, qf:
                                                QbeGen.QVal;
                                              isR, isL, folded: BOOLEAN;
-                                             lw, rw, mw: CARDINAL; .)
-    = Fact<t, q> { MulOp<op> Fact<t2, q2>
+                                             lw, rw, mw: CARDINAL;
+                                             lNext, lFalse, lDone, qr, qs:
+                                               QbeGen.QVal; .)
+    = Fact<t, q> { MulOp<op>            (. IF op = SymTab.OpAnd THEN
+                                             QbeGen.DelayBegin END; .)
+        Fact<t2, q2>                    (. IF op = SymTab.OpAnd THEN
+                                             QbeGen.DelayEnd END; .)
       (. IF op = SymTab.OpAnd THEN
+           (* short-circuit: if q is false the RHS is skipped *)
            IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
              t := SymTab.BoolType()
            ELSE SemError(212); t := SymTab.InvalidType END;
            IF t # SymTab.InvalidType THEN
-             QbeGen.NewTemp(qt);
-             QbeGen.Op3("and", qt, q, q2, FALSE);
-             QbeGen.CopyOp(qt, q)
-           ELSE QbeGen.CopyOp("0", q)
+             QbeGen.Slot4(qs);
+             QbeGen.NewLabel(lNext);
+             QbeGen.NewLabel(lFalse);
+             QbeGen.NewLabel(lDone);
+             QbeGen.Jnz(q, lNext, lFalse);
+             QbeGen.EmitLabel(lNext);
+             QbeGen.DelayFlush;
+             QbeGen.StoreW(qs, q2);
+             QbeGen.Jmp(lDone);
+             QbeGen.EmitLabel(lFalse);
+             QbeGen.StoreW(qs, "0");
+             QbeGen.Jmp(lDone);
+             QbeGen.EmitLabel(lDone);
+             QbeGen.LoadW(qs, qr);
+             QbeGen.CopyOp(qr, q)
+           ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
            END
          ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
  AND (SymTab.ClassOf(t) = SymTab.ClSet)

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 548 - 512
compiler/src/M2.lst


+ 15 - 0
compiler/src/QbeGen.def

@@ -43,6 +43,21 @@ PROCEDURE CloseModule;
    lowering waits for step 4: definitions, implementations,
    and any unit containing nested modules). *)
 
+PROCEDURE DelayBegin;
+PROCEDURE DelayEnd;
+PROCEDURE DelayFlush;
+(* Short-circuit AND/OR: DelayBegin buffers the RHS operand's code,
+   DelayEnd restores output, DelayFlush replays the buffer where the
+   branch needs it. *)
+
+PROCEDURE Slot4 (VAR s: QVal);
+(* s := fresh 4-byte stack slot (address).
+   Used to merge short-circuit AND/OR results: each branch stores into
+   the slot and the merge block loads it — robust regardless of how
+   many blocks the RHS operand's code spans. *)
+PROCEDURE StoreW (slot: ARRAY OF CHAR; val: ARRAY OF CHAR);
+PROCEDURE LoadW (slot: ARRAY OF CHAR; VAR q: QVal);
+
 PROCEDURE SetNoEmit (b: BOOLEAN);
 (* Suppresses all output while TRUE (nested procedures in 4.1:
    SymTab tracks, QbeGen stays silent). *)

+ 66 - 0
compiler/src/QbeGen.mod

@@ -51,6 +51,11 @@ VAR
   sessUsed : CARDINAL;
   nestBufs : ARRAY [0 .. 15] OF ARRAY [0 .. 65535] OF CHAR;
   nestUsed : ARRAY [0 .. 15] OF CARDINAL;
+  (* Short-circuit AND/OR: the RHS operand's code is buffered here
+     (delayTop > 0) and replayed inside the branch. *)
+  delayBuf : ARRAY [0 .. 15] OF ARRAY [0 .. 8191] OF CHAR;
+  delayUsed : ARRAY [0 .. 15] OF CARDINAL;
+  delayTop : CARDINAL;
   (* one buffer per nesting depth: each nested function stays
      contiguous no matter how deep the parse interleaves *)
   nPar : CARDINAL;   (* recorded formal params for the header *)
@@ -126,6 +131,20 @@ PROCEDURE WEmit (s: ARRAY OF CHAR; eol: BOOLEAN);
   VAR b, u, j : CARDINAL;
   BEGIN
     IF NOT opened OR noEmit THEN RETURN END;
+    IF delayTop > 0 THEN
+      b := delayTop - 1;
+      u := delayUsed[b]; j := 0;
+      WHILE (u < HIGH(delayBuf[b])) AND (j <= HIGH(s))
+            AND (s[j] # CHR(0)) DO
+        delayBuf[b][u] := s[j]; INC(u); INC(j)
+      END;
+      IF eol AND (u < HIGH(delayBuf[b])) THEN
+        delayBuf[b][u] := CHR(10); INC(u)
+      END;
+      IF u <= HIGH(delayBuf[b]) THEN delayBuf[b][u] := CHR(0) END;
+      delayUsed[b] := u;
+      RETURN
+    END;
     IF outSel = 0 THEN
       BufApp(sessBuf, sessUsed, s, eol);
       RETURN
@@ -159,6 +178,52 @@ PROCEDURE SetNoEmit (b: BOOLEAN);
     noEmit := b
   END SetNoEmit;
 
+PROCEDURE DelayBegin;
+(* Start buffering output (the RHS operand of a short-circuit AND/OR). *)
+  BEGIN
+    IF delayTop <= HIGH(delayBuf) THEN
+      delayUsed[delayTop] := 0;
+      delayBuf[delayTop][0] := CHR(0);
+      INC(delayTop)
+    END
+  END DelayBegin;
+
+PROCEDURE DelayEnd;
+(* Stop buffering (restore the previous output sink). *)
+  BEGIN
+    IF delayTop > 0 THEN DEC(delayTop) END
+  END DelayEnd;
+
+PROCEDURE DelayFlush;
+(* Emit the buffered RHS operand's code into the current sink.
+   DelayEnd already popped delayTop, so the just-used buffer index is
+   delayTop itself. *)
+  VAR b: CARDINAL;
+  BEGIN
+    b := delayTop;
+    IF b <= HIGH(delayBuf) THEN WEmit(delayBuf[b], FALSE) END
+  END DelayFlush;
+
+PROCEDURE Slot4 (VAR s: QVal);
+  BEGIN
+    NewTemp(s);
+    Revive;
+    W("  "); W(s); W(" =l alloc4 4"); WL("")
+  END Slot4;
+
+PROCEDURE StoreW (slot: ARRAY OF CHAR; val: ARRAY OF CHAR);
+  BEGIN
+    Revive;
+    W("  storew "); W(val); W(", "); WL(slot)
+  END StoreW;
+
+PROCEDURE LoadW (slot: ARRAY OF CHAR; VAR q: QVal);
+  BEGIN
+    NewTemp(q);
+    Revive;
+    W("  "); W(q); W(" =w loadw "); WL(slot)
+  END LoadW;
+
 PROCEDURE SetModule (name: ARRAY OF CHAR);
 (* Names the module whose globals are being emitted (QBE symbols
    become "<mod>_<name>" so separate modules never collide). *)
@@ -442,6 +507,7 @@ PROCEDURE OpenModule (name: ARRAY OF CHAR);
     nInit := 0;
     outSel := 0;
     sessUsed := 0; sessBuf[0] := CHR(0);
+    delayTop := 0;
     i := 0;
     WHILE i <= HIGH(nestBufs) DO
       nestBufs[i][0] := CHR(0); nestUsed[i] := 0; INC(i)

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů