Переглянути джерело

short-circuit AND/OR via deferred-output buffering + memory-slot merge (111/111)

- QbeGen: DelayBegin/DelayEnd/DelayFlush buffer the RHS operand's code and replay
  it in the branch; Slot4/StoreW/LoadW merge results across blocks (robust when
  the RHS spans blocks, e.g. set-membership trap checks).
- SimExpr (OR) / Term (AND): if a { r=1/0 } else { <RHS>; r=b }.
Eric Streit 2 тижнів тому
батько
коміт
5a1e3f73b2
4 змінених файлів з 573 додано та 528 видалено
  1. 17 9
      compiler/src/M2.atg
  2. 523 515
      compiler/src/M2.lst
  3. 8 0
      compiler/src/QbeGen.def
  4. 25 4
      compiler/src/QbeGen.mod

+ 17 - 9
compiler/src/M2.atg

@@ -1722,7 +1722,7 @@ PRODUCTIONS
                                              neg, isR, isL, folded:
                                                BOOLEAN;
                                              lw, rw, mw: CARDINAL;
-                                             lTrue, lNext, lDone:
+                                             lTrue, lNext, lDone, qr, qs:
                                                QbeGen.QVal; .)
     =                                   (. neg := FALSE; .)
       [ "+" | "-"                       (. neg := TRUE; .) ]
@@ -1746,17 +1746,21 @@ PRODUCTIONS
                t := SymTab.BoolType()
              ELSE SemError(212); t := SymTab.InvalidType END;
              IF t # SymTab.InvalidType THEN
+               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.CopyOp(q2, q);
+               QbeGen.StoreW(qs, q2);
                QbeGen.Jmp(lDone);
-               QbeGen.EmitLabel(lTrue);
-               QbeGen.CopyOp("1", q);
-               QbeGen.EmitLabel(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)
@@ -1830,7 +1834,7 @@ PRODUCTIONS
                                                QbeGen.QVal;
                                              isR, isL, folded: BOOLEAN;
                                              lw, rw, mw: CARDINAL;
-                                             lNext, lFalse, lDone:
+                                             lNext, lFalse, lDone, qr, qs:
                                                QbeGen.QVal; .)
     = Fact<t, q> { MulOp<op>            (. IF op = SymTab.OpAnd THEN
                                              QbeGen.DelayBegin END; .)
@@ -1842,17 +1846,21 @@ PRODUCTIONS
              t := SymTab.BoolType()
            ELSE SemError(212); t := SymTab.InvalidType END;
            IF t # SymTab.InvalidType THEN
+             QbeGen.Slot4(qs);
              QbeGen.NewLabel(lNext);
              QbeGen.NewLabel(lFalse);
              QbeGen.NewLabel(lDone);
              QbeGen.Jnz(q, lNext, lFalse);
              QbeGen.EmitLabel(lNext);
              QbeGen.DelayFlush;
-             QbeGen.CopyOp(q2, q);
+             QbeGen.StoreW(qs, q2);
              QbeGen.Jmp(lDone);
              QbeGen.EmitLabel(lFalse);
-             QbeGen.CopyOp("0", q);
-             QbeGen.EmitLabel(lDone)
+             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)

+ 523 - 515
compiler/src/M2.lst

@@ -1739,7 +1739,7 @@ Listing:
  1722                                               neg, isR, isL, folded:
  1723                                                 BOOLEAN;
  1724                                               lw, rw, mw: CARDINAL;
- 1725                                               lTrue, lNext, lDone:
+ 1725                                               lTrue, lNext, lDone, qr, qs:
  1726                                                 QbeGen.QVal; .)
  1727      =                                   (. neg := FALSE; .)
  1728        [ "+" | "-"                       (. neg := TRUE; .) ]
@@ -1763,521 +1763,529 @@ Listing:
  1746                 t := SymTab.BoolType()
  1747               ELSE SemError(212); t := SymTab.InvalidType END;
  1748               IF t # SymTab.InvalidType THEN
- 1749                 QbeGen.NewLabel(lTrue);
- 1750                 QbeGen.NewLabel(lNext);
- 1751                 QbeGen.NewLabel(lDone);
- 1752                 QbeGen.Jnz(q, lTrue, lNext);
- 1753                 QbeGen.EmitLabel(lNext);
- 1754                 QbeGen.DelayFlush;
- 1755                 QbeGen.CopyOp(q2, q);
+ 1749                 QbeGen.Slot4(qs);
+ 1750                 QbeGen.NewLabel(lTrue);
+ 1751                 QbeGen.NewLabel(lNext);
+ 1752                 QbeGen.NewLabel(lDone);
+ 1753                 QbeGen.Jnz(q, lTrue, lNext);
+ 1754                 QbeGen.EmitLabel(lTrue);
+ 1755                 QbeGen.StoreW(qs, "1");
  1756                 QbeGen.Jmp(lDone);
- 1757                 QbeGen.EmitLabel(lTrue);
- 1758                 QbeGen.CopyOp("1", q);
- 1759                 QbeGen.EmitLabel(lDone)
- 1760               ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
- 1761               END
- 1762             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 1763   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 1764   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1765               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 1766               mw := lw;
- 1767               IF rw > mw THEN mw := rw END;
- 1768               IF op = SymTab.OpAdd THEN
- 1769                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
- 1770               ELSE
- 1771                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
- 1772               END;
- 1773               t := SymTab.NewSet(
- 1774                      SymTab.NewSubR(0,
- 1775                        VAL(INTEGER, mw) * 32 - 1));
- 1776               QbeGen.CopyOp(qt, q)
- 1777             ELSE
- 1778               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
- 1779                 lt := t; rt := t2; t := res2
- 1780               ELSE SemError(211); t := SymTab.InvalidType END;
- 1781               IF t # SymTab.InvalidType THEN
- 1782                 isL := SymTab.IsLongFamily(t);
- 1783                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1784                 folded := FALSE;
- 1785                 IF (NOT isL) AND (NOT isR)
- 1786    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 1787                   IF op = SymTab.OpAdd THEN
- 1788                     folded := QbeGen.Fold2(0, q, q2, qf)
- 1789                   ELSE
- 1790                     folded := QbeGen.Fold2(1, q, q2, qf)
- 1791                   END
- 1792                 END;
- 1793                 IF folded THEN QbeGen.CopyOp(qf, q)
- 1794                 ELSE
- 1795                 IF isL THEN
- 1796                   IF SymTab.IsIntFamily(lt) THEN
- 1797                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 1798                   END;
- 1799                   IF SymTab.IsIntFamily(rt) THEN
- 1800                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 1801                   END;
- 1802                   QbeGen.NewTemp(qt);
- 1803                   IF op = SymTab.OpAdd THEN
- 1804                     QbeGen.Op3L("add", qt, q, q2)
- 1805                   ELSE
- 1806                     QbeGen.Op3L("sub", qt, q, q2)
- 1807                   END
- 1808                 ELSE
- 1809                   QbeGen.NewTemp(qt);
- 1810                   IF op = SymTab.OpAdd THEN
- 1811                     QbeGen.Op3("add", qt, q, q2, isR)
- 1812                   ELSE
- 1813                     QbeGen.Op3("sub", qt, q, q2, isR)
- 1814                   END
- 1815                 END;
- 1816                 QbeGen.CopyOp(qt, q)
- 1817                 END
- 1818               ELSE QbeGen.CopyOp("0", q)
- 1819               END
- 1820             END; .) } .
- 1821    AddOp<VAR op: INTEGER>
- 1822      = "+"                               (. op := SymTab.OpAdd; .)
- 1823      | "-"                               (. op := SymTab.OpSub; .)
- 1824      | "OR"                              (. op := SymTab.OpOr; .) .
- 1825    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1826                                          (. VAR t2, res2, lt, rt:
- 1827                                                 SymTab.TypeIndex;
- 1828                                               op: INTEGER;
- 1829                                               q2, qt, wq, qf:
- 1830                                                 QbeGen.QVal;
- 1831                                               isR, isL, folded: BOOLEAN;
- 1832                                               lw, rw, mw: CARDINAL;
- 1833                                               lNext, lFalse, lDone:
- 1834                                                 QbeGen.QVal; .)
- 1835      = Fact<t, q> { MulOp<op>            (. IF op = SymTab.OpAnd THEN
- 1836                                               QbeGen.DelayBegin END; .)
- 1837          Fact<t2, q2>                    (. IF op = SymTab.OpAnd THEN
- 1838                                               QbeGen.DelayEnd END; .)
- 1839        (. IF op = SymTab.OpAnd THEN
- 1840             (* short-circuit: if q is false the RHS is skipped *)
- 1841             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 1842               t := SymTab.BoolType()
- 1843             ELSE SemError(212); t := SymTab.InvalidType END;
- 1844             IF t # SymTab.InvalidType THEN
- 1845               QbeGen.NewLabel(lNext);
- 1846               QbeGen.NewLabel(lFalse);
- 1847               QbeGen.NewLabel(lDone);
- 1848               QbeGen.Jnz(q, lNext, lFalse);
- 1849               QbeGen.EmitLabel(lNext);
- 1850               QbeGen.DelayFlush;
- 1851               QbeGen.CopyOp(q2, q);
- 1852               QbeGen.Jmp(lDone);
- 1853               QbeGen.EmitLabel(lFalse);
- 1854               QbeGen.CopyOp("0", q);
- 1855               QbeGen.EmitLabel(lDone)
- 1856             ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
- 1857             END
- 1858           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 1859   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 1860   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1861             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 1862             mw := lw;
- 1863             IF rw > mw THEN mw := rw END;
- 1864             IF op = SymTab.OpTimes THEN
- 1865               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
- 1866             ELSE
- 1867               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
- 1868             END;
- 1869             t := SymTab.NewSet(
- 1870                    SymTab.NewSubR(0,
- 1871                      VAL(INTEGER, mw) * 32 - 1));
- 1872             QbeGen.CopyOp(qt, q)
- 1873           ELSE
- 1874             IF SymTab.ArithCheck(t, t2,
- 1875                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
- 1876                  res2) THEN
- 1877               lt := t; rt := t2; t := res2
- 1878             ELSE SemError(211); t := SymTab.InvalidType END;
- 1879             IF t # SymTab.InvalidType THEN
- 1880               isL := SymTab.IsLongFamily(t);
- 1881               isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1882               folded := FALSE;
- 1883               IF (NOT isL) AND (NOT isR)
- 1884    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 1885                 IF op = SymTab.OpTimes THEN
- 1886                   folded := QbeGen.Fold2(2, q, q2, qf)
- 1887                 ELSIF op = SymTab.OpDiv THEN
- 1888                   folded := QbeGen.Fold2(3, q, q2, qf)
- 1889                 ELSIF op = SymTab.OpMod THEN
- 1890                   folded := QbeGen.Fold2(4, q, q2, qf)
- 1891                 END
- 1892               END;
- 1893               IF folded THEN QbeGen.CopyOp(qf, q)
- 1894               ELSE
- 1895               IF isL THEN
- 1896                 IF SymTab.IsIntFamily(lt) THEN
- 1897                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 1898                 END;
- 1899                 IF SymTab.IsIntFamily(rt) THEN
- 1900                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 1901                 END;
- 1902                 QbeGen.NewTemp(qt);
- 1903                 IF op = SymTab.OpTimes THEN
- 1904                   QbeGen.Op3L("mul", qt, q, q2)
- 1905                 ELSIF (op = SymTab.OpDiv)
- 1906                    OR (op = SymTab.OpSlash) THEN
- 1907                   QbeGen.Op3L("div", qt, q, q2)
- 1908                 ELSE
- 1909                   QbeGen.Op3L("rem", qt, q, q2)
- 1910                 END
- 1911               ELSE
- 1912                 QbeGen.NewTemp(qt);
- 1913                 IF op = SymTab.OpTimes THEN
- 1914                   QbeGen.Op3("mul", qt, q, q2, isR)
- 1915                 ELSIF (op = SymTab.OpDiv)
- 1916                    OR (op = SymTab.OpSlash) THEN
- 1917                   QbeGen.Op3("div", qt, q, q2, isR)
- 1918                 ELSE
- 1919                   QbeGen.Op3("rem", qt, q, q2, isR)
- 1920                 END
- 1921               END;
- 1922               QbeGen.CopyOp(qt, q)
- 1923               END
- 1924             ELSE QbeGen.CopyOp("0", q)
- 1925             END
- 1926           END; .) } .
- 1927    MulOp<VAR op: INTEGER>
- 1928      = "*"                               (. op := SymTab.OpTimes; .)
- 1929      | "/"                               (. op := SymTab.OpSlash; .)
- 1930      | "DIV"                             (. op := SymTab.OpDiv; .)
- 1931      | "MOD"                             (. op := SymTab.OpMod; .)
- 1932      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
- 1933    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1934                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
- 1935                                               et, dt, t2, st, ct2:
- 1936                                                 SymTab.TypeIndex;
- 1937                                               dk: INTEGER;
- 1938                                               qd, q2, sq, qa, qm0, qr:
- 1939                                                 QbeGen.QVal;
- 1940                                               qn, vn: SymTab.Name;
- 1941                                               vt: SymTab.TypeIndex;
- 1942                                               c1, c2: INTEGER;
- 1943                                               called, isHigh, sfx, isCh:
- 1944                                                 BOOLEAN; .)
- 1945      = integer                           (. LexString(s);
- 1946                                             QbeGen.NormInt(s, q);
- 1947                                             t := SymTab.IntType(); .)
- 1948      | charConst                         (. LexString(s);
- 1949                                             QbeGen.NormLit(s, q, isCh);
- 1950                                             t := SymTab.CharType(); .)
- 1951      | real                              (. LexString(s);
- 1952                                             QbeGen.NormReal(s, q);
- 1953                                             t := SymTab.RealType(); .)
- 1954      | string                            (. LexString(s);
- 1955                                             IF SymTab.StrLen(s) = 3 THEN
- 1956                                               t := SymTab.CharType();
- 1957                                               QbeGen.IntStr(
- 1958                                                 QbeGen.CharVal(s), q)
- 1959                                             ELSE t := SymTab.NewStr();
- 1960                                               QbeGen.DeclStr(s, q);
- 1961                                               (* a literal's value IS its
- 1962                                                  static descriptor address *)
- 1963                                               QbeGen.NoteAddr(q, q)
- 1964                                             END; .)
- 1965      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
- 1966                                             t := dt;
- 1967                                             IF sfx THEN
- 1968                                               IF dt =
- 1969                                                  SymTab.InvalidType THEN
- 1970                                                 QbeGen.CopyOp("0", q)
- 1971                                               ELSIF (SymTab.ClassOf(dt) =
- 1972                                                      SymTab.ClRecord)
- 1973                                                  OR (SymTab.ClassOf(dt) =
- 1974                                                      SymTab.ClSet)
- 1975                                                  OR (SymTab.ClassOf(dt) =
- 1976                                                      SymTab.ClArray)
- 1977                                                  OR (SymTab.ClassOf(dt) =
- 1978                                                      SymTab.ClClass) THEN
- 1979                                                 QbeGen.CopyOp(qd, q)
- 1980                                               ELSE QbeGen.ElemLoad(qd, dt,
- 1981                                                 q)
- 1982                                               END
- 1983                                             ELSE QbeGen.CopyOp(qd, q)
- 1984                                             END;
- 1985                                             IF (dk = SymTab.KindVar)
- 1986                                                OR (dk = SymTab.KindParam)
- 1987                                                OR (dk =
- 1988                                                   SymTab.KindField) THEN
- 1989                                               IF sfx THEN
- 1990                                                 QbeGen.NoteAddr(q, qd)
- 1991                                               ELSE
- 1992                                                 QbeGen.AddrOf(qn, qa);
- 1993                                                 QbeGen.NoteAddr(q, qa)
- 1994                                               END
- 1995                                             ELSIF sfx
- 1996   AND (dt #
- 1997                                                   SymTab.InvalidType)
- 1998   AND ((SymTab.ClassOf(dt) =
- 1999                                                    SymTab.ClArray)
- 2000                                                   OR (SymTab.ClassOf(dt) =
- 2001                                                       SymTab.ClSet)
- 2002                                                   OR (SymTab.ClassOf(dt) =
- 2003                                                       SymTab.ClRecord)) THEN
- 2004                                               QbeGen.NoteAddr(qd, qd)
- 2005                                             END; .)
- 2006        [ TypedSetLit<dt, q>              (. t := dt; .) ]
- 2007        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
- 2008                                          (. t := ct2;
- 2009                                             QbeGen.CopyOp(q2, q); .) ]
- 2010                                          (. IF NOT called
- 2011   AND (dk = SymTab.KindProc) THEN
- 2012                                               (* bare zero-arg function
- 2013                                                  call (parentheses may be
- 2014                                                  omitted); a proper or
- 2015                                                  parameterised proc here
- 2016                                                  is 230 *)
- 2017                                               IF (SymTab.ProcNPar(qn) = 0)
- 2018   AND (SymTab.ProcRes(qn) #
- 2019                                                     SymTab.InvalidType) THEN
- 2020                                                 QbeGen.Mangled(qn,
- 2021                                                   SymTab.ProcUid(qn), qm0);
- 2022                                                 QbeGen.CallBegin(qm0,
- 2023                                                   SymTab.ProcRes(qn),
- 2024                                                   SymTab.ProcDepthOf(qn),
- 2025                                                   SymTab.IsExternal(qn));
- 2026                                                 QbeGen.CallEnd(TRUE, q);
- 2027                                                 t := SymTab.ProcRes(qn)
- 2028                                               ELSE
- 2029                                                 (* procedure used as a
- 2030                                                    value (assign to a
- 2031                                                    procedure variable):
- 2032                                                    its code address *)
- 2033                                                 t := SymTab.ProcTypeOf(qn);
- 2034                                                 QbeGen.Mangled(qn,
- 2035                                                   SymTab.ProcUid(qn), qm0);
- 2036                                                 QbeGen.ProcAddr(qm0, q)
- 2037                                               END
- 2038                                             END; .)
- 2039      | ( "HIGH"                          (. isHigh := TRUE; .)
- 2040        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
- 2041        "(" Design<dt, dk, qd, qn, sfx> ")"
- 2042                                          (. IF dt = SymTab.InvalidType THEN
- 2043                                             ELSIF SymTab.ClassOf(dt) #
- 2044                                                   SymTab.ClArray THEN
- 2045                                               SemError(217);
- 2046                                               t := SymTab.InvalidType;
- 2047                                               QbeGen.CopyOp("0", q)
- 2048                                             ELSE
- 2049                                               IF isHigh THEN
- 2050                                                 IF SymTab.IsOpenArray(dt) THEN
- 2051                                                   QbeGen.OpenHi(qd, qr)
- 2052                                                 ELSE
- 2053                                                   QbeGen.IntStr(
- 2054                                                     SymTab.ArrayHi(dt), qr)
- 2055                                                 END
- 2056                                               ELSE
- 2057                                                 IF SymTab.IsOpenArray(dt) THEN
- 2058                                                   QbeGen.LoadCount(qd, qr)
- 2059                                                 ELSE
- 2060                                                   QbeGen.IntStr(VAL(
- 2061                                                     INTEGER,
- 2062                                                     SymTab.ArrayLen(dt)),
- 2063                                                     qr)
- 2064                                                 END
- 2065                                               END;
- 2066                                                t := SymTab.IntType();
- 2067                                                QbeGen.CopyOp(qr, q)
- 2068                                              END; .)
- 2069      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 2070                                          (. IF dt = SymTab.InvalidType THEN
- 2071                                               t := SymTab.InvalidType;
- 2072                                               QbeGen.CopyOp("0", q)
- 2073                                             ELSE
- 2074                                               QbeGen.IntStr(VAL(INTEGER,
- 2075                                                 SymTab.ObjectSize(dt)), q);
- 2076                                               t := SymTab.IntType()
- 2077                                             END; .)
- 2078      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 2079                                          (. IF dt = SymTab.InvalidType THEN
- 2080                                               t := SymTab.InvalidType;
- 2081                                               QbeGen.CopyOp("0", q)
- 2082                                             ELSE
- 2083                                               IF sfx THEN
- 2084                                                 QbeGen.CopyOp(qd, q)
- 2085                                               ELSIF (dk = SymTab.KindVar)
- 2086                                                  OR (dk = SymTab.KindParam) THEN
- 2087                                                 QbeGen.AddrOf(qn, q)
- 2088                                               ELSE SemError(230);
- 2089                                                 QbeGen.CopyOp("0", q)
- 2090                                               END;
- 2091                                               t := SymTab.AddrType()
- 2092                                             END; .)
- 2093      | "CHR" "(" Expr<et, q> ")"
- 2094                                          (. IF (et # SymTab.InvalidType)
- 2095   AND NOT SymTab.IsIntFamily(et) THEN
- 2096                                               SemError(211) END;
- 2097                                             t := SymTab.CharType(); .)
- 2098      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
- 2099                                          (. IF et # SymTab.InvalidType THEN
- 2100                                               IF (SymTab.ClassOf(et) #
- 2101                                                   SymTab.ClChar)
- 2102   AND (SymTab.ClassOf(et) #
- 2103                                                     SymTab.ClBool)
- 2104   AND (SymTab.ClassOf(et) #
- 2105                                                     SymTab.ClEnum)
- 2106   AND NOT SymTab.IsIntFamily(et) THEN
- 2107                                                 SemError(211) END
- 2108                                             END;
- 2109                                             t := SymTab.IntType(); .)
- 2110      | "CAP" "(" Expr<et, q> ")"
- 2111                                          (. QbeGen.CapQ(q, qa);
- 2112                                             QbeGen.CopyOp(qa, q);
- 2113                                             t := SymTab.CharType(); .)
- 2114      | "ABS" "(" Expr<et, q> ")"
- 2115                                          (. IF (et # SymTab.InvalidType)
- 2116   AND NOT SymTab.IsIntFamily(et)
- 2117   AND (SymTab.ClassOf(et) #
- 2118                                                  SymTab.ClReal) THEN
- 2119                                               SemError(211)
- 2120                                             ELSE QbeGen.AbsQ(q, qa,
- 2121                                                    SymTab.ClassOf(et) =
- 2122                                                      SymTab.ClReal);
- 2123                                               QbeGen.CopyOp(qa, q)
- 2124                                             END;
- 2125                                             t := et; .)
- 2126      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
- 2127                                          (. IF NOT SymTab.Lookup(vn) THEN
- 2128                                               SemError(201);
- 2129                                               t := SymTab.InvalidType
- 2130                                             ELSE vt := SymTab.SymType(vn);
- 2131                                               IF vt = SymTab.InvalidType THEN
- 2132                                                 t := SymTab.InvalidType
- 2133                                               ELSIF et =
- 2134                                                  SymTab.InvalidType THEN
- 2135                                                 t := vt
- 2136                                               ELSE
- 2137                                                 c1 := SymTab.ClassOf(et);
- 2138                                                 c2 := SymTab.ClassOf(vt);
- 2139                                                 IF ((c1 = SymTab.ClInt)
- 2140                                                     OR (c1 =
- 2141                                                        SymTab.ClChar)
- 2142                                                     OR (c1 =
- 2143                                                        SymTab.ClBool)
- 2144                                                     OR (c1 =
- 2145                                                        SymTab.ClEnum))
- 2146   AND ((c2 = SymTab.ClInt)
- 2147                                                     OR (c2 =
- 2148                                                        SymTab.ClChar)
- 2149                                                     OR (c2 =
- 2150                                                        SymTab.ClBool)
- 2151                                                     OR (c2 =
- 2152                                                        SymTab.ClEnum)) THEN
- 2153                                                   t := vt
- 2154                                                 ELSIF (c1 = SymTab.ClPtr)
- 2155   AND (c2 = SymTab.ClPtr) THEN
- 2156                                                   t := vt
- 2157                                                 ELSIF (c1 = SymTab.ClReal)
- 2158   AND (c2 = SymTab.ClReal) THEN
- 2159                                                   t := vt
- 2160                                                 ELSE SemError(230);
- 2161                                                   t := SymTab.InvalidType
- 2162                                                 END
- 2163                                               END
- 2164                                             END; .)
- 2165      | "(" Expr<et, q> ")"               (. t := et; .)
- 2166      | SetLit<st, sq>                    (. t := st;
- 2167                                             QbeGen.CopyOp(sq, q); .)
- 2168      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
- 2169                                               t := SymTab.BoolType()
- 2170                                             ELSE SemError(212);
- 2171                                               t := SymTab.InvalidType END;
- 2172                                             IF t # SymTab.InvalidType THEN
- 2173                                               QbeGen.NotQ(q2, q)
- 2174                                             ELSE QbeGen.CopyOp("0", q)
- 2175                                             END; .) .
- 2176    (* Set literals are SET OF [0..255] (8 words); elements validated
- 2177       0..255 statically when foldable (222 otherwise), runtime trap
- 2178       for computed elements. Ranges always lower via SetRange. *)
- 2179    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2180      = "{"                               (. t := SymTab.NewSet(
- 2181                                               SymTab.NewSubR(0, 255));
- 2182                                             QbeGen.NewSetTemp(8, q);
- 2183                                             QbeGen.SetZero(q, 8); .)
- 2184        [ SetElem<t, q> { "," SetElem<t, q> } ]
- 2185        "}" .
- 2186    (* Typed set constructor: TypeName{ elems } — e.g. BITSET{0},
- 2187       BITSET{}.  The declared type (not SET OF [0..255]) sets the
- 2188       width and element span. *)
- 2189    TypedSetLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2190                                          (. VAR nw: CARDINAL; .)
- 2191      = "{"                               (. IF SymTab.ClassOf(vt) #
- 2192                                                SymTab.ClSet THEN
- 2193                                               SemError(230); nw := 8
- 2194                                             ELSE nw := SymTab.SetWords(vt);
- 2195                                               IF nw = 0 THEN nw := 8 END
- 2196                                             END;
- 2197                                             QbeGen.NewSetTemp(nw, q);
- 2198                                             QbeGen.SetZero(q, nw); .)
- 2199        [ SetElem<vt, q> { "," SetElem<vt, q> } ]
- 2200        "}" .
- 2201    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
- 2202                                               qe, q2: QbeGen.QVal;
- 2203                                               v, v2: INTEGER;
- 2204                                               lo: INTEGER;
- 2205                                               span: CARDINAL;
- 2206                                               cl, cl2: INTEGER;
- 2207                                               hasR: BOOLEAN; .)
- 2208      =                                   (. hasR := FALSE; .)
- 2209        Expr<et, qe>
- 2210        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
- 2211                                          (. lo := SymTab.SetBaseLo(st);
- 2212                                             span := SymTab.SetCount(st);
- 2213                                             IF (et = SymTab.InvalidType)
- 2214                                                OR (hasR AND (et2 =
- 2215                                                   SymTab.InvalidType)) THEN
- 2216                                             ELSE cl :=
- 2217                                                    SymTab.ClassOf(et);
- 2218                                               IF hasR THEN
- 2219                                                 cl2 :=
- 2220                                                   SymTab.ClassOf(et2)
- 2221                                               ELSE cl2 := SymTab.ClInt
- 2222                                               END;
- 2223                                               IF ((cl # SymTab.ClInt)
- 2224   AND (cl # SymTab.ClChar)
- 2225   AND (cl # SymTab.ClBool))
- 2226                                                  OR (hasR AND 
- 2227                                                     ((cl2
- 2228                                                       # SymTab.ClInt)
- 2229   AND (cl2
- 2230                                                        # SymTab.ClChar)
- 2231   AND (cl2
- 2232                                                        # SymTab.ClBool))) THEN
- 2233                                                 SemError(222)
- 2234                                               ELSIF hasR
- 2235   AND SymTab.ConstInt(qe, v)
- 2236   AND SymTab.ConstInt(q2,
- 2237                                                     v2)
- 2238   AND ((v < lo)
- 2239                                                     OR (v2 < lo)
- 2240                                                     OR (v >= lo +
- 2241                                                        VAL(INTEGER, span))
- 2242                                                     OR (v2 >= lo +
- 2243                                                        VAL(INTEGER, span))
- 2244                                                     OR (v > v2)) THEN
- 2245                                                 SemError(222)
- 2246                                                ELSIF hasR THEN
- 2247                                                  QbeGen.SetRange(sq, qe, q2,
- 2248                                                    lo, span)
- 2249                                                ELSIF SymTab.ConstInt(qe,
- 2250                                                        v)
- 2251   AND ((v < lo)
- 2252                                                      OR (v >= lo +
- 2253                                                         VAL(INTEGER,
- 2254                                                           span))) THEN
- 2255                                                  SemError(222)
- 2256                                                ELSE QbeGen.SetBit(sq, qe,
- 2257                                                  lo, span)
- 2258                                               END
- 2259                                             END; .) .
- 2260    GetIdent<VAR n: SymTab.Name>
- 2261      = ident                             (. LexName(n); .) .
- 2262  
- 2263  END M2.
+ 1757                 QbeGen.EmitLabel(lNext);
+ 1758                 QbeGen.DelayFlush;
+ 1759                 QbeGen.StoreW(qs, q2);
+ 1760                 QbeGen.Jmp(lDone);
+ 1761                 QbeGen.EmitLabel(lDone);
+ 1762                 QbeGen.LoadW(qs, qr);
+ 1763                 QbeGen.CopyOp(qr, q)
+ 1764               ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
+ 1765               END
+ 1766             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 1767   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1768   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1769               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 1770               mw := lw;
+ 1771               IF rw > mw THEN mw := rw END;
+ 1772               IF op = SymTab.OpAdd THEN
+ 1773                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
+ 1774               ELSE
+ 1775                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
+ 1776               END;
+ 1777               t := SymTab.NewSet(
+ 1778                      SymTab.NewSubR(0,
+ 1779                        VAL(INTEGER, mw) * 32 - 1));
+ 1780               QbeGen.CopyOp(qt, q)
+ 1781             ELSE
+ 1782               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
+ 1783                 lt := t; rt := t2; t := res2
+ 1784               ELSE SemError(211); t := SymTab.InvalidType END;
+ 1785               IF t # SymTab.InvalidType THEN
+ 1786                 isL := SymTab.IsLongFamily(t);
+ 1787                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1788                 folded := FALSE;
+ 1789                 IF (NOT isL) AND (NOT isR)
+ 1790    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 1791                   IF op = SymTab.OpAdd THEN
+ 1792                     folded := QbeGen.Fold2(0, q, q2, qf)
+ 1793                   ELSE
+ 1794                     folded := QbeGen.Fold2(1, q, q2, qf)
+ 1795                   END
+ 1796                 END;
+ 1797                 IF folded THEN QbeGen.CopyOp(qf, q)
+ 1798                 ELSE
+ 1799                 IF isL THEN
+ 1800                   IF SymTab.IsIntFamily(lt) THEN
+ 1801                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 1802                   END;
+ 1803                   IF SymTab.IsIntFamily(rt) THEN
+ 1804                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 1805                   END;
+ 1806                   QbeGen.NewTemp(qt);
+ 1807                   IF op = SymTab.OpAdd THEN
+ 1808                     QbeGen.Op3L("add", qt, q, q2)
+ 1809                   ELSE
+ 1810                     QbeGen.Op3L("sub", qt, q, q2)
+ 1811                   END
+ 1812                 ELSE
+ 1813                   QbeGen.NewTemp(qt);
+ 1814                   IF op = SymTab.OpAdd THEN
+ 1815                     QbeGen.Op3("add", qt, q, q2, isR)
+ 1816                   ELSE
+ 1817                     QbeGen.Op3("sub", qt, q, q2, isR)
+ 1818                   END
+ 1819                 END;
+ 1820                 QbeGen.CopyOp(qt, q)
+ 1821                 END
+ 1822               ELSE QbeGen.CopyOp("0", q)
+ 1823               END
+ 1824             END; .) } .
+ 1825    AddOp<VAR op: INTEGER>
+ 1826      = "+"                               (. op := SymTab.OpAdd; .)
+ 1827      | "-"                               (. op := SymTab.OpSub; .)
+ 1828      | "OR"                              (. op := SymTab.OpOr; .) .
+ 1829    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1830                                          (. VAR t2, res2, lt, rt:
+ 1831                                                 SymTab.TypeIndex;
+ 1832                                               op: INTEGER;
+ 1833                                               q2, qt, wq, qf:
+ 1834                                                 QbeGen.QVal;
+ 1835                                               isR, isL, folded: BOOLEAN;
+ 1836                                               lw, rw, mw: CARDINAL;
+ 1837                                               lNext, lFalse, lDone, qr, qs:
+ 1838                                                 QbeGen.QVal; .)
+ 1839      = Fact<t, q> { MulOp<op>            (. IF op = SymTab.OpAnd THEN
+ 1840                                               QbeGen.DelayBegin END; .)
+ 1841          Fact<t2, q2>                    (. IF op = SymTab.OpAnd THEN
+ 1842                                               QbeGen.DelayEnd END; .)
+ 1843        (. IF op = SymTab.OpAnd THEN
+ 1844             (* short-circuit: if q is false the RHS is skipped *)
+ 1845             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 1846               t := SymTab.BoolType()
+ 1847             ELSE SemError(212); t := SymTab.InvalidType END;
+ 1848             IF t # SymTab.InvalidType THEN
+ 1849               QbeGen.Slot4(qs);
+ 1850               QbeGen.NewLabel(lNext);
+ 1851               QbeGen.NewLabel(lFalse);
+ 1852               QbeGen.NewLabel(lDone);
+ 1853               QbeGen.Jnz(q, lNext, lFalse);
+ 1854               QbeGen.EmitLabel(lNext);
+ 1855               QbeGen.DelayFlush;
+ 1856               QbeGen.StoreW(qs, q2);
+ 1857               QbeGen.Jmp(lDone);
+ 1858               QbeGen.EmitLabel(lFalse);
+ 1859               QbeGen.StoreW(qs, "0");
+ 1860               QbeGen.Jmp(lDone);
+ 1861               QbeGen.EmitLabel(lDone);
+ 1862               QbeGen.LoadW(qs, qr);
+ 1863               QbeGen.CopyOp(qr, q)
+ 1864             ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
+ 1865             END
+ 1866           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 1867   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1868   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1869             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 1870             mw := lw;
+ 1871             IF rw > mw THEN mw := rw END;
+ 1872             IF op = SymTab.OpTimes THEN
+ 1873               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
+ 1874             ELSE
+ 1875               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
+ 1876             END;
+ 1877             t := SymTab.NewSet(
+ 1878                    SymTab.NewSubR(0,
+ 1879                      VAL(INTEGER, mw) * 32 - 1));
+ 1880             QbeGen.CopyOp(qt, q)
+ 1881           ELSE
+ 1882             IF SymTab.ArithCheck(t, t2,
+ 1883                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
+ 1884                  res2) THEN
+ 1885               lt := t; rt := t2; t := res2
+ 1886             ELSE SemError(211); t := SymTab.InvalidType END;
+ 1887             IF t # SymTab.InvalidType THEN
+ 1888               isL := SymTab.IsLongFamily(t);
+ 1889               isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1890               folded := FALSE;
+ 1891               IF (NOT isL) AND (NOT isR)
+ 1892    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 1893                 IF op = SymTab.OpTimes THEN
+ 1894                   folded := QbeGen.Fold2(2, q, q2, qf)
+ 1895                 ELSIF op = SymTab.OpDiv THEN
+ 1896                   folded := QbeGen.Fold2(3, q, q2, qf)
+ 1897                 ELSIF op = SymTab.OpMod THEN
+ 1898                   folded := QbeGen.Fold2(4, q, q2, qf)
+ 1899                 END
+ 1900               END;
+ 1901               IF folded THEN QbeGen.CopyOp(qf, q)
+ 1902               ELSE
+ 1903               IF isL THEN
+ 1904                 IF SymTab.IsIntFamily(lt) THEN
+ 1905                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 1906                 END;
+ 1907                 IF SymTab.IsIntFamily(rt) THEN
+ 1908                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 1909                 END;
+ 1910                 QbeGen.NewTemp(qt);
+ 1911                 IF op = SymTab.OpTimes THEN
+ 1912                   QbeGen.Op3L("mul", qt, q, q2)
+ 1913                 ELSIF (op = SymTab.OpDiv)
+ 1914                    OR (op = SymTab.OpSlash) THEN
+ 1915                   QbeGen.Op3L("div", qt, q, q2)
+ 1916                 ELSE
+ 1917                   QbeGen.Op3L("rem", qt, q, q2)
+ 1918                 END
+ 1919               ELSE
+ 1920                 QbeGen.NewTemp(qt);
+ 1921                 IF op = SymTab.OpTimes THEN
+ 1922                   QbeGen.Op3("mul", qt, q, q2, isR)
+ 1923                 ELSIF (op = SymTab.OpDiv)
+ 1924                    OR (op = SymTab.OpSlash) THEN
+ 1925                   QbeGen.Op3("div", qt, q, q2, isR)
+ 1926                 ELSE
+ 1927                   QbeGen.Op3("rem", qt, q, q2, isR)
+ 1928                 END
+ 1929               END;
+ 1930               QbeGen.CopyOp(qt, q)
+ 1931               END
+ 1932             ELSE QbeGen.CopyOp("0", q)
+ 1933             END
+ 1934           END; .) } .
+ 1935    MulOp<VAR op: INTEGER>
+ 1936      = "*"                               (. op := SymTab.OpTimes; .)
+ 1937      | "/"                               (. op := SymTab.OpSlash; .)
+ 1938      | "DIV"                             (. op := SymTab.OpDiv; .)
+ 1939      | "MOD"                             (. op := SymTab.OpMod; .)
+ 1940      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
+ 1941    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1942                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
+ 1943                                               et, dt, t2, st, ct2:
+ 1944                                                 SymTab.TypeIndex;
+ 1945                                               dk: INTEGER;
+ 1946                                               qd, q2, sq, qa, qm0, qr:
+ 1947                                                 QbeGen.QVal;
+ 1948                                               qn, vn: SymTab.Name;
+ 1949                                               vt: SymTab.TypeIndex;
+ 1950                                               c1, c2: INTEGER;
+ 1951                                               called, isHigh, sfx, isCh:
+ 1952                                                 BOOLEAN; .)
+ 1953      = integer                           (. LexString(s);
+ 1954                                             QbeGen.NormInt(s, q);
+ 1955                                             t := SymTab.IntType(); .)
+ 1956      | charConst                         (. LexString(s);
+ 1957                                             QbeGen.NormLit(s, q, isCh);
+ 1958                                             t := SymTab.CharType(); .)
+ 1959      | real                              (. LexString(s);
+ 1960                                             QbeGen.NormReal(s, q);
+ 1961                                             t := SymTab.RealType(); .)
+ 1962      | string                            (. LexString(s);
+ 1963                                             IF SymTab.StrLen(s) = 3 THEN
+ 1964                                               t := SymTab.CharType();
+ 1965                                               QbeGen.IntStr(
+ 1966                                                 QbeGen.CharVal(s), q)
+ 1967                                             ELSE t := SymTab.NewStr();
+ 1968                                               QbeGen.DeclStr(s, q);
+ 1969                                               (* a literal's value IS its
+ 1970                                                  static descriptor address *)
+ 1971                                               QbeGen.NoteAddr(q, q)
+ 1972                                             END; .)
+ 1973      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
+ 1974                                             t := dt;
+ 1975                                             IF sfx THEN
+ 1976                                               IF dt =
+ 1977                                                  SymTab.InvalidType THEN
+ 1978                                                 QbeGen.CopyOp("0", q)
+ 1979                                               ELSIF (SymTab.ClassOf(dt) =
+ 1980                                                      SymTab.ClRecord)
+ 1981                                                  OR (SymTab.ClassOf(dt) =
+ 1982                                                      SymTab.ClSet)
+ 1983                                                  OR (SymTab.ClassOf(dt) =
+ 1984                                                      SymTab.ClArray)
+ 1985                                                  OR (SymTab.ClassOf(dt) =
+ 1986                                                      SymTab.ClClass) THEN
+ 1987                                                 QbeGen.CopyOp(qd, q)
+ 1988                                               ELSE QbeGen.ElemLoad(qd, dt,
+ 1989                                                 q)
+ 1990                                               END
+ 1991                                             ELSE QbeGen.CopyOp(qd, q)
+ 1992                                             END;
+ 1993                                             IF (dk = SymTab.KindVar)
+ 1994                                                OR (dk = SymTab.KindParam)
+ 1995                                                OR (dk =
+ 1996                                                   SymTab.KindField) THEN
+ 1997                                               IF sfx THEN
+ 1998                                                 QbeGen.NoteAddr(q, qd)
+ 1999                                               ELSE
+ 2000                                                 QbeGen.AddrOf(qn, qa);
+ 2001                                                 QbeGen.NoteAddr(q, qa)
+ 2002                                               END
+ 2003                                             ELSIF sfx
+ 2004   AND (dt #
+ 2005                                                   SymTab.InvalidType)
+ 2006   AND ((SymTab.ClassOf(dt) =
+ 2007                                                    SymTab.ClArray)
+ 2008                                                   OR (SymTab.ClassOf(dt) =
+ 2009                                                       SymTab.ClSet)
+ 2010                                                   OR (SymTab.ClassOf(dt) =
+ 2011                                                       SymTab.ClRecord)) THEN
+ 2012                                               QbeGen.NoteAddr(qd, qd)
+ 2013                                             END; .)
+ 2014        [ TypedSetLit<dt, q>              (. t := dt; .) ]
+ 2015        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
+ 2016                                          (. t := ct2;
+ 2017                                             QbeGen.CopyOp(q2, q); .) ]
+ 2018                                          (. IF NOT called
+ 2019   AND (dk = SymTab.KindProc) THEN
+ 2020                                               (* bare zero-arg function
+ 2021                                                  call (parentheses may be
+ 2022                                                  omitted); a proper or
+ 2023                                                  parameterised proc here
+ 2024                                                  is 230 *)
+ 2025                                               IF (SymTab.ProcNPar(qn) = 0)
+ 2026   AND (SymTab.ProcRes(qn) #
+ 2027                                                     SymTab.InvalidType) THEN
+ 2028                                                 QbeGen.Mangled(qn,
+ 2029                                                   SymTab.ProcUid(qn), qm0);
+ 2030                                                 QbeGen.CallBegin(qm0,
+ 2031                                                   SymTab.ProcRes(qn),
+ 2032                                                   SymTab.ProcDepthOf(qn),
+ 2033                                                   SymTab.IsExternal(qn));
+ 2034                                                 QbeGen.CallEnd(TRUE, q);
+ 2035                                                 t := SymTab.ProcRes(qn)
+ 2036                                               ELSE
+ 2037                                                 (* procedure used as a
+ 2038                                                    value (assign to a
+ 2039                                                    procedure variable):
+ 2040                                                    its code address *)
+ 2041                                                 t := SymTab.ProcTypeOf(qn);
+ 2042                                                 QbeGen.Mangled(qn,
+ 2043                                                   SymTab.ProcUid(qn), qm0);
+ 2044                                                 QbeGen.ProcAddr(qm0, q)
+ 2045                                               END
+ 2046                                             END; .)
+ 2047      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 2048        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 2049        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2050                                          (. IF dt = SymTab.InvalidType THEN
+ 2051                                             ELSIF SymTab.ClassOf(dt) #
+ 2052                                                   SymTab.ClArray THEN
+ 2053                                               SemError(217);
+ 2054                                               t := SymTab.InvalidType;
+ 2055                                               QbeGen.CopyOp("0", q)
+ 2056                                             ELSE
+ 2057                                               IF isHigh THEN
+ 2058                                                 IF SymTab.IsOpenArray(dt) THEN
+ 2059                                                   QbeGen.OpenHi(qd, qr)
+ 2060                                                 ELSE
+ 2061                                                   QbeGen.IntStr(
+ 2062                                                     SymTab.ArrayHi(dt), qr)
+ 2063                                                 END
+ 2064                                               ELSE
+ 2065                                                 IF SymTab.IsOpenArray(dt) THEN
+ 2066                                                   QbeGen.LoadCount(qd, qr)
+ 2067                                                 ELSE
+ 2068                                                   QbeGen.IntStr(VAL(
+ 2069                                                     INTEGER,
+ 2070                                                     SymTab.ArrayLen(dt)),
+ 2071                                                     qr)
+ 2072                                                 END
+ 2073                                               END;
+ 2074                                                t := SymTab.IntType();
+ 2075                                                QbeGen.CopyOp(qr, q)
+ 2076                                              END; .)
+ 2077      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2078                                          (. IF dt = SymTab.InvalidType THEN
+ 2079                                               t := SymTab.InvalidType;
+ 2080                                               QbeGen.CopyOp("0", q)
+ 2081                                             ELSE
+ 2082                                               QbeGen.IntStr(VAL(INTEGER,
+ 2083                                                 SymTab.ObjectSize(dt)), q);
+ 2084                                               t := SymTab.IntType()
+ 2085                                             END; .)
+ 2086      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2087                                          (. IF dt = SymTab.InvalidType THEN
+ 2088                                               t := SymTab.InvalidType;
+ 2089                                               QbeGen.CopyOp("0", q)
+ 2090                                             ELSE
+ 2091                                               IF sfx THEN
+ 2092                                                 QbeGen.CopyOp(qd, q)
+ 2093                                               ELSIF (dk = SymTab.KindVar)
+ 2094                                                  OR (dk = SymTab.KindParam) THEN
+ 2095                                                 QbeGen.AddrOf(qn, q)
+ 2096                                               ELSE SemError(230);
+ 2097                                                 QbeGen.CopyOp("0", q)
+ 2098                                               END;
+ 2099                                               t := SymTab.AddrType()
+ 2100                                             END; .)
+ 2101      | "CHR" "(" Expr<et, q> ")"
+ 2102                                          (. IF (et # SymTab.InvalidType)
+ 2103   AND NOT SymTab.IsIntFamily(et) THEN
+ 2104                                               SemError(211) END;
+ 2105                                             t := SymTab.CharType(); .)
+ 2106      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 2107                                          (. IF et # SymTab.InvalidType THEN
+ 2108                                               IF (SymTab.ClassOf(et) #
+ 2109                                                   SymTab.ClChar)
+ 2110   AND (SymTab.ClassOf(et) #
+ 2111                                                     SymTab.ClBool)
+ 2112   AND (SymTab.ClassOf(et) #
+ 2113                                                     SymTab.ClEnum)
+ 2114   AND NOT SymTab.IsIntFamily(et) THEN
+ 2115                                                 SemError(211) END
+ 2116                                             END;
+ 2117                                             t := SymTab.IntType(); .)
+ 2118      | "CAP" "(" Expr<et, q> ")"
+ 2119                                          (. QbeGen.CapQ(q, qa);
+ 2120                                             QbeGen.CopyOp(qa, q);
+ 2121                                             t := SymTab.CharType(); .)
+ 2122      | "ABS" "(" Expr<et, q> ")"
+ 2123                                          (. IF (et # SymTab.InvalidType)
+ 2124   AND NOT SymTab.IsIntFamily(et)
+ 2125   AND (SymTab.ClassOf(et) #
+ 2126                                                  SymTab.ClReal) THEN
+ 2127                                               SemError(211)
+ 2128                                             ELSE QbeGen.AbsQ(q, qa,
+ 2129                                                    SymTab.ClassOf(et) =
+ 2130                                                      SymTab.ClReal);
+ 2131                                               QbeGen.CopyOp(qa, q)
+ 2132                                             END;
+ 2133                                             t := et; .)
+ 2134      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
+ 2135                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 2136                                               SemError(201);
+ 2137                                               t := SymTab.InvalidType
+ 2138                                             ELSE vt := SymTab.SymType(vn);
+ 2139                                               IF vt = SymTab.InvalidType THEN
+ 2140                                                 t := SymTab.InvalidType
+ 2141                                               ELSIF et =
+ 2142                                                  SymTab.InvalidType THEN
+ 2143                                                 t := vt
+ 2144                                               ELSE
+ 2145                                                 c1 := SymTab.ClassOf(et);
+ 2146                                                 c2 := SymTab.ClassOf(vt);
+ 2147                                                 IF ((c1 = SymTab.ClInt)
+ 2148                                                     OR (c1 =
+ 2149                                                        SymTab.ClChar)
+ 2150                                                     OR (c1 =
+ 2151                                                        SymTab.ClBool)
+ 2152                                                     OR (c1 =
+ 2153                                                        SymTab.ClEnum))
+ 2154   AND ((c2 = SymTab.ClInt)
+ 2155                                                     OR (c2 =
+ 2156                                                        SymTab.ClChar)
+ 2157                                                     OR (c2 =
+ 2158                                                        SymTab.ClBool)
+ 2159                                                     OR (c2 =
+ 2160                                                        SymTab.ClEnum)) THEN
+ 2161                                                   t := vt
+ 2162                                                 ELSIF (c1 = SymTab.ClPtr)
+ 2163   AND (c2 = SymTab.ClPtr) THEN
+ 2164                                                   t := vt
+ 2165                                                 ELSIF (c1 = SymTab.ClReal)
+ 2166   AND (c2 = SymTab.ClReal) THEN
+ 2167                                                   t := vt
+ 2168                                                 ELSE SemError(230);
+ 2169                                                   t := SymTab.InvalidType
+ 2170                                                 END
+ 2171                                               END
+ 2172                                             END; .)
+ 2173      | "(" Expr<et, q> ")"               (. t := et; .)
+ 2174      | SetLit<st, sq>                    (. t := st;
+ 2175                                             QbeGen.CopyOp(sq, q); .)
+ 2176      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
+ 2177                                               t := SymTab.BoolType()
+ 2178                                             ELSE SemError(212);
+ 2179                                               t := SymTab.InvalidType END;
+ 2180                                             IF t # SymTab.InvalidType THEN
+ 2181                                               QbeGen.NotQ(q2, q)
+ 2182                                             ELSE QbeGen.CopyOp("0", q)
+ 2183                                             END; .) .
+ 2184    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 2185       0..255 statically when foldable (222 otherwise), runtime trap
+ 2186       for computed elements. Ranges always lower via SetRange. *)
+ 2187    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2188      = "{"                               (. t := SymTab.NewSet(
+ 2189                                               SymTab.NewSubR(0, 255));
+ 2190                                             QbeGen.NewSetTemp(8, q);
+ 2191                                             QbeGen.SetZero(q, 8); .)
+ 2192        [ SetElem<t, q> { "," SetElem<t, q> } ]
+ 2193        "}" .
+ 2194    (* Typed set constructor: TypeName{ elems } — e.g. BITSET{0},
+ 2195       BITSET{}.  The declared type (not SET OF [0..255]) sets the
+ 2196       width and element span. *)
+ 2197    TypedSetLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2198                                          (. VAR nw: CARDINAL; .)
+ 2199      = "{"                               (. IF SymTab.ClassOf(vt) #
+ 2200                                                SymTab.ClSet THEN
+ 2201                                               SemError(230); nw := 8
+ 2202                                             ELSE nw := SymTab.SetWords(vt);
+ 2203                                               IF nw = 0 THEN nw := 8 END
+ 2204                                             END;
+ 2205                                             QbeGen.NewSetTemp(nw, q);
+ 2206                                             QbeGen.SetZero(q, nw); .)
+ 2207        [ SetElem<vt, q> { "," SetElem<vt, q> } ]
+ 2208        "}" .
+ 2209    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
+ 2210                                               qe, q2: QbeGen.QVal;
+ 2211                                               v, v2: INTEGER;
+ 2212                                               lo: INTEGER;
+ 2213                                               span: CARDINAL;
+ 2214                                               cl, cl2: INTEGER;
+ 2215                                               hasR: BOOLEAN; .)
+ 2216      =                                   (. hasR := FALSE; .)
+ 2217        Expr<et, qe>
+ 2218        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
+ 2219                                          (. lo := SymTab.SetBaseLo(st);
+ 2220                                             span := SymTab.SetCount(st);
+ 2221                                             IF (et = SymTab.InvalidType)
+ 2222                                                OR (hasR AND (et2 =
+ 2223                                                   SymTab.InvalidType)) THEN
+ 2224                                             ELSE cl :=
+ 2225                                                    SymTab.ClassOf(et);
+ 2226                                               IF hasR THEN
+ 2227                                                 cl2 :=
+ 2228                                                   SymTab.ClassOf(et2)
+ 2229                                               ELSE cl2 := SymTab.ClInt
+ 2230                                               END;
+ 2231                                               IF ((cl # SymTab.ClInt)
+ 2232   AND (cl # SymTab.ClChar)
+ 2233   AND (cl # SymTab.ClBool))
+ 2234                                                  OR (hasR AND 
+ 2235                                                     ((cl2
+ 2236                                                       # SymTab.ClInt)
+ 2237   AND (cl2
+ 2238                                                        # SymTab.ClChar)
+ 2239   AND (cl2
+ 2240                                                        # SymTab.ClBool))) THEN
+ 2241                                                 SemError(222)
+ 2242                                               ELSIF hasR
+ 2243   AND SymTab.ConstInt(qe, v)
+ 2244   AND SymTab.ConstInt(q2,
+ 2245                                                     v2)
+ 2246   AND ((v < lo)
+ 2247                                                     OR (v2 < lo)
+ 2248                                                     OR (v >= lo +
+ 2249                                                        VAL(INTEGER, span))
+ 2250                                                     OR (v2 >= lo +
+ 2251                                                        VAL(INTEGER, span))
+ 2252                                                     OR (v > v2)) THEN
+ 2253                                                 SemError(222)
+ 2254                                                ELSIF hasR THEN
+ 2255                                                  QbeGen.SetRange(sq, qe, q2,
+ 2256                                                    lo, span)
+ 2257                                                ELSIF SymTab.ConstInt(qe,
+ 2258                                                        v)
+ 2259   AND ((v < lo)
+ 2260                                                      OR (v >= lo +
+ 2261                                                         VAL(INTEGER,
+ 2262                                                           span))) THEN
+ 2263                                                  SemError(222)
+ 2264                                                ELSE QbeGen.SetBit(sq, qe,
+ 2265                                                  lo, span)
+ 2266                                               END
+ 2267                                             END; .) .
+ 2268    GetIdent<VAR n: SymTab.Name>
+ 2269      = ident                             (. LexName(n); .) .
+ 2270  
+ 2271  END M2.
 
     0 errors
 

+ 8 - 0
compiler/src/QbeGen.def

@@ -50,6 +50,14 @@ PROCEDURE DelayFlush;
    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). *)

+ 25 - 4
compiler/src/QbeGen.mod

@@ -195,14 +195,35 @@ PROCEDURE DelayEnd;
   END DelayEnd;
 
 PROCEDURE DelayFlush;
-(* Emit the buffered RHS operand's code into the current sink. *)
+(* 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
-    IF delayTop = 0 THEN RETURN END;
-    b := delayTop - 1;
-    WEmit(delayBuf[b], FALSE)
+    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). *)