| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- IMPLEMENTATION MODULE QbeGen;
- IMPORT FileIO, SymTab;
- VAR
- out : FileIO.File;
- opened : BOOLEAN;
- inBody : BOOLEAN;
- nTemp : CARDINAL;
- nLab : CARDINAL;
- loopTop : CARDINAL;
- loopSt : ARRAY [0 .. 15] OF QVal;
- noqbe : CARDINAL;
- nR : CARDINAL;
- rNames : ARRAY [0 .. 31] OF QVal;
- rVals : ARRAY [0 .. 31] OF QVal;
- (* ---------------- small string utilities ---------------- *)
- PROCEDURE Len (s: ARRAY OF CHAR): CARDINAL;
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- WHILE (i < HIGH(s)) & (s[i] # 0C) DO INC(i) END;
- RETURN i
- END Len;
- PROCEDURE Cpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- WHILE (i < HIGH(d)) & (i < HIGH(s)) & (s[i] # 0C) DO
- d[i] := s[i]; INC(i)
- END;
- IF i <= HIGH(d) THEN d[i] := 0C END
- END Cpy;
- PROCEDURE App (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
- VAR i, j : CARDINAL;
- BEGIN
- i := 0;
- WHILE (i <= HIGH(d)) & (d[i] # 0C) DO INC(i) END;
- j := 0;
- WHILE (i < HIGH(d)) & (j < HIGH(s)) & (s[j] # 0C) DO
- d[i] := s[j]; INC(i); INC(j)
- END;
- IF i <= HIGH(d) THEN d[i] := 0C END
- END App;
- PROCEDURE W (s: ARRAY OF CHAR);
- BEGIN
- IF opened THEN FileIO.WriteString(out, s) END
- END W;
- PROCEDURE WL (s: ARRAY OF CHAR);
- BEGIN
- W(s);
- IF opened THEN FileIO.WriteLn(out) END
- END WL;
- PROCEDURE AppNum (VAR d: ARRAY OF CHAR; v: CARDINAL);
- (* Appends v in decimal to d. *)
- VAR buf : ARRAY [0 .. 15] OF CHAR;
- n, i, L : CARDINAL;
- BEGIN
- n := 0;
- IF v = 0 THEN buf[0] := "0"; n := 1 END;
- WHILE (v > 0) & (n <= HIGH(buf)) DO
- buf[n] := CHR(ORD("0") + v MOD 10); v := v DIV 10; INC(n)
- END;
- i := n;
- WHILE i > 0 DO
- DEC(i);
- L := Len(d);
- IF L < HIGH(d) THEN d[L] := buf[i]; d[L + 1] := 0C END
- END
- END AppNum;
- (* ---------------- exported helpers ---------------- *)
- PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
- BEGIN
- Cpy(d, s)
- END CopyOp;
- PROCEDURE IntStr (v: INTEGER; VAR s: QVal);
- VAR neg : BOOLEAN;
- mag : CARDINAL;
- buf : ARRAY [0 .. 15] OF CHAR;
- n, i, L : CARDINAL;
- t : CHAR;
- BEGIN
- neg := v < 0;
- IF neg THEN mag := VAL(CARDINAL, -v) ELSE mag := VAL(CARDINAL, v) END;
- n := 0;
- IF mag = 0 THEN buf[0] := "0"; n := 1 END;
- WHILE (mag > 0) & (n < HIGH(buf)) DO
- buf[n] := CHR(ORD("0") + mag MOD 10); mag := mag DIV 10; INC(n)
- END;
- i := 0;
- WHILE i < n DIV 2 DO
- t := buf[i]; buf[i] := buf[n - 1 - i]; buf[n - 1 - i] := t; INC(i)
- END;
- s[0] := 0C;
- IF neg THEN App(s, "-") END;
- i := 0;
- WHILE i < n DO
- L := Len(s);
- IF L < HIGH(s) THEN s[L] := buf[i]; s[L + 1] := 0C END;
- INC(i)
- END
- END IntStr;
- PROCEDURE HexVal (ch: CHAR): INTEGER;
- BEGIN
- IF (ch >= "0") & (ch <= "9") THEN RETURN ORD(ch) - ORD("0") END;
- IF (ch >= "A") & (ch <= "F") THEN RETURN ORD(ch) - ORD("A") + 10 END;
- IF (ch >= "a") & (ch <= "f") THEN RETURN ORD(ch) - ORD("a") + 10 END;
- RETURN 0
- END HexVal;
- PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal);
- (* "0FFH" -> "255", plain decimals are copied through. *)
- VAR n, i : CARDINAL;
- v : INTEGER;
- BEGIN
- n := Len(s);
- IF (n > 0) & ((s[n - 1] = "H") OR (s[n - 1] = "h")) THEN
- v := 0; i := 0;
- WHILE i < n - 1 DO v := v * 16 + HexVal(s[i]); INC(i) END;
- IntStr(v, d)
- ELSE
- Cpy(d, s)
- END
- END NormInt;
- PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal);
- BEGIN
- Cpy(d, "d_");
- App(d, s)
- END NormReal;
- PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER;
- BEGIN
- IF Len(s) >= 2 THEN RETURN ORD(s[1]) END;
- RETURN 0
- END CharVal;
- PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal);
- (* Safe for a and q being the same variable. *)
- VAR i, j, L : CARDINAL;
- tmp : QVal;
- BEGIN
- Cpy(tmp, a);
- IF Len(tmp) = 0 THEN Cpy(q, "0"); RETURN END;
- IF tmp[0] = "-" THEN
- i := 1; j := 0;
- WHILE (tmp[i] # 0C) & (j < HIGH(q)) DO
- q[j] := tmp[i]; INC(i); INC(j)
- END;
- IF j <= HIGH(q) THEN q[j] := 0C END
- ELSIF (tmp[0] = "d") & (Len(tmp) > 1) & (tmp[1] = "_") THEN
- Cpy(q, "d_-");
- i := 2;
- WHILE tmp[i] # 0C DO
- L := Len(q);
- IF L < HIGH(q) THEN q[L] := tmp[i]; q[L + 1] := 0C END;
- INC(i)
- END
- ELSE
- Cpy(q, "-");
- App(q, tmp)
- END
- END NegFold;
- PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN;
- VAR c : CHAR;
- BEGIN
- IF Len(s) = 0 THEN RETURN FALSE END;
- c := s[0];
- RETURN ((c >= "0") & (c <= "9")) OR (c = "-") OR (c = "d")
- END IsImm;
- PROCEDURE IsNeg (s: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- RETURN (Len(s) > 0) & (s[0] = "-")
- END IsNeg;
- (* ---------------- module / data section ---------------- *)
- PROCEDURE OpenModule (name: ARRAY OF CHAR);
- VAR fname : ARRAY [0 .. 127] OF CHAR;
- BEGIN
- fname[0] := 0C;
- App(fname, "gen_qbe/");
- App(fname, name);
- App(fname, ".ssa");
- FileIO.Open(out, fname, TRUE);
- opened := FileIO.Okay;
- inBody := FALSE;
- nTemp := 0; nLab := 0; loopTop := 0; noqbe := 0; nR := 0;
- WL("# QBE IR generated by the SimpleQ backend");
- WL("")
- END OpenModule;
- PROCEDURE DataLine (name: ARRAY OF CHAR; isReal: BOOLEAN; init: ARRAY OF CHAR);
- BEGIN
- IF ~opened THEN RETURN END;
- W("data $"); W(name);
- IF isReal THEN W(" = { d ") ELSE W(" = { w ") END;
- W(init);
- WL(" }")
- END DataLine;
- PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER);
- BEGIN
- IF SymTab.ClassOf(t) = SymTab.ClReal THEN DataLine(name, TRUE, "0")
- ELSE DataLine(name, FALSE, "0")
- END
- END DeclVar;
- PROCEDURE IsZeroReal (val: ARRAY OF CHAR): BOOLEAN;
- (* TRUE when the "d_..." literal denotes zero (checked textually). *)
- VAR i : CARDINAL;
- seen : BOOLEAN;
- ch : CHAR;
- BEGIN
- i := 0;
- IF (Len(val) > 1) & (val[0] = "d") & (val[1] = "_") THEN i := 2 END;
- seen := FALSE;
- WHILE val[i] # 0C DO
- ch := val[i];
- IF (ch >= "0") & (ch <= "9") THEN
- seen := TRUE;
- IF ch # "0" THEN RETURN FALSE END
- ELSIF (ch # ".") & (ch # "E") & (ch # "e")
- & (ch # "+") & (ch # "-") THEN
- RETURN FALSE
- END;
- INC(i)
- END;
- RETURN seen
- END IsZeroReal;
- PROCEDURE DeclConst (name: ARRAY OF CHAR; val: ARRAY OF CHAR; t: INTEGER);
- VAR cls : INTEGER;
- init : QVal;
- BEGIN
- cls := SymTab.ClassOf(t);
- IF (cls = SymTab.ClStr) OR ~IsImm(val) THEN
- DeclVar(name, t); RETURN
- END;
- IF cls = SymTab.ClReal THEN
- IF IsZeroReal(val) THEN DataLine(name, TRUE, "0")
- ELSE
- DataLine(name, TRUE, "0");
- IF nR <= HIGH(rNames) THEN
- Cpy(rNames[nR], name); Cpy(rVals[nR], val); INC(nR)
- END
- END
- ELSE DataLine(name, FALSE, val)
- END
- END DeclConst;
- (* ---------------- function body ---------------- *)
- PROCEDURE BeginBody;
- VAR i : CARDINAL;
- t : QVal;
- BEGIN
- IF ~opened OR inBody THEN RETURN END;
- WL("");
- WL("export function w $main() {");
- WL("@start");
- inBody := TRUE;
- i := 0;
- WHILE i < nR DO
- NewTemp(t);
- W(" "); W(t); W(" =d copy "); WL(rVals[i]);
- StoreVar(rNames[i], t, TRUE);
- INC(i)
- END
- END BeginBody;
- PROCEDURE EndModule;
- BEGIN
- IF ~opened THEN RETURN END;
- IF ~inBody THEN BeginBody END;
- IF SymTab.Lookup("ExitCode")
- & (SymTab.SymKind("ExitCode") = SymTab.KindVar)
- & SymTab.IsIntFamily(SymTab.SymType("ExitCode")) THEN
- WL(" %ec =w loadw $ExitCode");
- WL(" ret %ec")
- ELSE
- WL(" ret 0")
- END;
- WL("}");
- FileIO.Close(out);
- opened := FALSE
- END EndModule;
- (* ---------------- temporaries, labels, jumps ---------------- *)
- PROCEDURE NewTemp (VAR t: QVal);
- BEGIN
- Cpy(t, "%t");
- AppNum(t, nTemp);
- INC(nTemp)
- END NewTemp;
- PROCEDURE NewLabel (VAR l: QVal);
- BEGIN
- Cpy(l, "@L");
- AppNum(l, nLab);
- INC(nLab)
- END NewLabel;
- PROCEDURE EmitLabel (l: ARRAY OF CHAR);
- BEGIN
- WL(l)
- END EmitLabel;
- PROCEDURE Jmp (l: ARRAY OF CHAR);
- BEGIN
- W(" jmp "); WL(l)
- END Jmp;
- PROCEDURE Jnz (c, t, f: ARRAY OF CHAR);
- BEGIN
- W(" jnz "); W(c); W(", "); W(t); W(", "); WL(f)
- END Jnz;
- (* ---------------- data movement and operators ---------------- *)
- PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal);
- BEGIN
- NewTemp(q);
- W(" "); W(q);
- IF isReal THEN W(" =d loadd $") ELSE W(" =w loadw $") END;
- WL(name)
- END LoadVar;
- PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN);
- BEGIN
- IF isReal THEN W(" stored ") ELSE W(" storew ") END;
- W(q); W(", $"); WL(name)
- END StoreVar;
- PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR;
- isReal: BOOLEAN);
- BEGIN
- W(" "); W(res);
- IF isReal THEN W(" =d ") ELSE W(" =w ") END;
- W(mn); W(" "); W(l); W(", "); WL(r)
- END Op3;
- PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal;
- isReal: BOOLEAN);
- VAR mn : ARRAY [0 .. 7] OF CHAR;
- BEGIN
- mn[0] := 0C;
- IF isReal THEN
- IF op = SymTab.OpEq THEN Cpy(mn, "ceqd")
- ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cned")
- ELSIF op = SymTab.OpLt THEN Cpy(mn, "cltd")
- ELSIF op = SymTab.OpLe THEN Cpy(mn, "cled")
- ELSIF op = SymTab.OpGt THEN Cpy(mn, "cgtd")
- ELSE Cpy(mn, "cged")
- END
- ELSE
- IF op = SymTab.OpEq THEN Cpy(mn, "ceqw")
- ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cnew")
- ELSIF op = SymTab.OpLt THEN Cpy(mn, "csltw")
- ELSIF op = SymTab.OpLe THEN Cpy(mn, "cslew")
- ELSIF op = SymTab.OpGt THEN Cpy(mn, "csgtw")
- ELSE Cpy(mn, "csgew")
- END
- END;
- NewTemp(q);
- Op3(mn, q, l, r, FALSE)
- END Cmp;
- PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
- BEGIN
- NewTemp(q);
- IF isReal THEN Op3("sub", q, "d_0.0", a, TRUE)
- ELSE Op3("sub", q, "0", a, FALSE)
- END
- END NegQ;
- PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
- BEGIN
- NewTemp(q);
- Op3("xor", q, "1", a, FALSE)
- END NotQ;
- PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal);
- BEGIN
- NewTemp(q);
- W(" "); W(q); W(" =d swtof "); WL(a)
- END ConvIR;
- (* ---------------- loop stack and 230 guard ---------------- *)
- PROCEDURE PushLoop (exit: ARRAY OF CHAR);
- BEGIN
- IF loopTop <= HIGH(loopSt) THEN
- Cpy(loopSt[loopTop], exit); INC(loopTop)
- END
- END PushLoop;
- PROCEDURE PopLoop;
- BEGIN
- IF loopTop > 0 THEN DEC(loopTop) END
- END PopLoop;
- PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;
- BEGIN
- IF loopTop = 0 THEN RETURN FALSE END;
- Cpy(exit, loopSt[loopTop - 1]);
- RETURN TRUE
- END TopLoop;
- PROCEDURE NoQbeEnter;
- BEGIN
- INC(noqbe)
- END NoQbeEnter;
- PROCEDURE NoQbeExit;
- BEGIN
- IF noqbe > 0 THEN DEC(noqbe) END
- END NoQbeExit;
- PROCEDURE NoQbe (): BOOLEAN;
- BEGIN
- RETURN noqbe > 0
- END NoQbe;
- PROCEDURE Remark (s: ARRAY OF CHAR);
- BEGIN
- W("# "); WL(s)
- END Remark;
- BEGIN
- opened := FALSE;
- inBody := FALSE;
- nTemp := 0; nLab := 0; loopTop := 0; noqbe := 0; nR := 0
- END QbeGen.
|