QbeGen.mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. IMPLEMENTATION MODULE QbeGen;
  2. IMPORT FileIO, SymTab;
  3. VAR
  4. out : FileIO.File;
  5. opened : BOOLEAN;
  6. inBody : BOOLEAN;
  7. nTemp : CARDINAL;
  8. nLab : CARDINAL;
  9. loopTop : CARDINAL;
  10. loopSt : ARRAY [0 .. 15] OF QVal;
  11. noqbe : CARDINAL;
  12. nR : CARDINAL;
  13. rNames : ARRAY [0 .. 31] OF QVal;
  14. rVals : ARRAY [0 .. 31] OF QVal;
  15. (* ---------------- small string utilities ---------------- *)
  16. PROCEDURE Len (s: ARRAY OF CHAR): CARDINAL;
  17. VAR i : CARDINAL;
  18. BEGIN
  19. i := 0;
  20. WHILE (i < HIGH(s)) & (s[i] # 0C) DO INC(i) END;
  21. RETURN i
  22. END Len;
  23. PROCEDURE Cpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  24. VAR i : CARDINAL;
  25. BEGIN
  26. i := 0;
  27. WHILE (i < HIGH(d)) & (i < HIGH(s)) & (s[i] # 0C) DO
  28. d[i] := s[i]; INC(i)
  29. END;
  30. IF i <= HIGH(d) THEN d[i] := 0C END
  31. END Cpy;
  32. PROCEDURE App (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  33. VAR i, j : CARDINAL;
  34. BEGIN
  35. i := 0;
  36. WHILE (i <= HIGH(d)) & (d[i] # 0C) DO INC(i) END;
  37. j := 0;
  38. WHILE (i < HIGH(d)) & (j < HIGH(s)) & (s[j] # 0C) DO
  39. d[i] := s[j]; INC(i); INC(j)
  40. END;
  41. IF i <= HIGH(d) THEN d[i] := 0C END
  42. END App;
  43. PROCEDURE W (s: ARRAY OF CHAR);
  44. BEGIN
  45. IF opened THEN FileIO.WriteString(out, s) END
  46. END W;
  47. PROCEDURE WL (s: ARRAY OF CHAR);
  48. BEGIN
  49. W(s);
  50. IF opened THEN FileIO.WriteLn(out) END
  51. END WL;
  52. PROCEDURE AppNum (VAR d: ARRAY OF CHAR; v: CARDINAL);
  53. (* Appends v in decimal to d. *)
  54. VAR buf : ARRAY [0 .. 15] OF CHAR;
  55. n, i, L : CARDINAL;
  56. BEGIN
  57. n := 0;
  58. IF v = 0 THEN buf[0] := "0"; n := 1 END;
  59. WHILE (v > 0) & (n <= HIGH(buf)) DO
  60. buf[n] := CHR(ORD("0") + v MOD 10); v := v DIV 10; INC(n)
  61. END;
  62. i := n;
  63. WHILE i > 0 DO
  64. DEC(i);
  65. L := Len(d);
  66. IF L < HIGH(d) THEN d[L] := buf[i]; d[L + 1] := 0C END
  67. END
  68. END AppNum;
  69. (* ---------------- exported helpers ---------------- *)
  70. PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  71. BEGIN
  72. Cpy(d, s)
  73. END CopyOp;
  74. PROCEDURE IntStr (v: INTEGER; VAR s: QVal);
  75. VAR neg : BOOLEAN;
  76. mag : CARDINAL;
  77. buf : ARRAY [0 .. 15] OF CHAR;
  78. n, i, L : CARDINAL;
  79. t : CHAR;
  80. BEGIN
  81. neg := v < 0;
  82. IF neg THEN mag := VAL(CARDINAL, -v) ELSE mag := VAL(CARDINAL, v) END;
  83. n := 0;
  84. IF mag = 0 THEN buf[0] := "0"; n := 1 END;
  85. WHILE (mag > 0) & (n < HIGH(buf)) DO
  86. buf[n] := CHR(ORD("0") + mag MOD 10); mag := mag DIV 10; INC(n)
  87. END;
  88. i := 0;
  89. WHILE i < n DIV 2 DO
  90. t := buf[i]; buf[i] := buf[n - 1 - i]; buf[n - 1 - i] := t; INC(i)
  91. END;
  92. s[0] := 0C;
  93. IF neg THEN App(s, "-") END;
  94. i := 0;
  95. WHILE i < n DO
  96. L := Len(s);
  97. IF L < HIGH(s) THEN s[L] := buf[i]; s[L + 1] := 0C END;
  98. INC(i)
  99. END
  100. END IntStr;
  101. PROCEDURE HexVal (ch: CHAR): INTEGER;
  102. BEGIN
  103. IF (ch >= "0") & (ch <= "9") THEN RETURN ORD(ch) - ORD("0") END;
  104. IF (ch >= "A") & (ch <= "F") THEN RETURN ORD(ch) - ORD("A") + 10 END;
  105. IF (ch >= "a") & (ch <= "f") THEN RETURN ORD(ch) - ORD("a") + 10 END;
  106. RETURN 0
  107. END HexVal;
  108. PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal);
  109. (* "0FFH" -> "255", plain decimals are copied through. *)
  110. VAR n, i : CARDINAL;
  111. v : INTEGER;
  112. BEGIN
  113. n := Len(s);
  114. IF (n > 0) & ((s[n - 1] = "H") OR (s[n - 1] = "h")) THEN
  115. v := 0; i := 0;
  116. WHILE i < n - 1 DO v := v * 16 + HexVal(s[i]); INC(i) END;
  117. IntStr(v, d)
  118. ELSE
  119. Cpy(d, s)
  120. END
  121. END NormInt;
  122. PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal);
  123. BEGIN
  124. Cpy(d, "d_");
  125. App(d, s)
  126. END NormReal;
  127. PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER;
  128. BEGIN
  129. IF Len(s) >= 2 THEN RETURN ORD(s[1]) END;
  130. RETURN 0
  131. END CharVal;
  132. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal);
  133. (* Safe for a and q being the same variable. *)
  134. VAR i, j, L : CARDINAL;
  135. tmp : QVal;
  136. BEGIN
  137. Cpy(tmp, a);
  138. IF Len(tmp) = 0 THEN Cpy(q, "0"); RETURN END;
  139. IF tmp[0] = "-" THEN
  140. i := 1; j := 0;
  141. WHILE (tmp[i] # 0C) & (j < HIGH(q)) DO
  142. q[j] := tmp[i]; INC(i); INC(j)
  143. END;
  144. IF j <= HIGH(q) THEN q[j] := 0C END
  145. ELSIF (tmp[0] = "d") & (Len(tmp) > 1) & (tmp[1] = "_") THEN
  146. Cpy(q, "d_-");
  147. i := 2;
  148. WHILE tmp[i] # 0C DO
  149. L := Len(q);
  150. IF L < HIGH(q) THEN q[L] := tmp[i]; q[L + 1] := 0C END;
  151. INC(i)
  152. END
  153. ELSE
  154. Cpy(q, "-");
  155. App(q, tmp)
  156. END
  157. END NegFold;
  158. PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN;
  159. VAR c : CHAR;
  160. BEGIN
  161. IF Len(s) = 0 THEN RETURN FALSE END;
  162. c := s[0];
  163. RETURN ((c >= "0") & (c <= "9")) OR (c = "-") OR (c = "d")
  164. END IsImm;
  165. PROCEDURE IsNeg (s: ARRAY OF CHAR): BOOLEAN;
  166. BEGIN
  167. RETURN (Len(s) > 0) & (s[0] = "-")
  168. END IsNeg;
  169. (* ---------------- module / data section ---------------- *)
  170. PROCEDURE OpenModule (name: ARRAY OF CHAR);
  171. VAR fname : ARRAY [0 .. 127] OF CHAR;
  172. BEGIN
  173. fname[0] := 0C;
  174. App(fname, "gen_qbe/");
  175. App(fname, name);
  176. App(fname, ".ssa");
  177. FileIO.Open(out, fname, TRUE);
  178. opened := FileIO.Okay;
  179. inBody := FALSE;
  180. nTemp := 0; nLab := 0; loopTop := 0; noqbe := 0; nR := 0;
  181. WL("# QBE IR generated by the SimpleQ backend");
  182. WL("")
  183. END OpenModule;
  184. PROCEDURE DataLine (name: ARRAY OF CHAR; isReal: BOOLEAN; init: ARRAY OF CHAR);
  185. BEGIN
  186. IF ~opened THEN RETURN END;
  187. W("data $"); W(name);
  188. IF isReal THEN W(" = { d ") ELSE W(" = { w ") END;
  189. W(init);
  190. WL(" }")
  191. END DataLine;
  192. PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER);
  193. BEGIN
  194. IF SymTab.ClassOf(t) = SymTab.ClReal THEN DataLine(name, TRUE, "0")
  195. ELSE DataLine(name, FALSE, "0")
  196. END
  197. END DeclVar;
  198. PROCEDURE IsZeroReal (val: ARRAY OF CHAR): BOOLEAN;
  199. (* TRUE when the "d_..." literal denotes zero (checked textually). *)
  200. VAR i : CARDINAL;
  201. seen : BOOLEAN;
  202. ch : CHAR;
  203. BEGIN
  204. i := 0;
  205. IF (Len(val) > 1) & (val[0] = "d") & (val[1] = "_") THEN i := 2 END;
  206. seen := FALSE;
  207. WHILE val[i] # 0C DO
  208. ch := val[i];
  209. IF (ch >= "0") & (ch <= "9") THEN
  210. seen := TRUE;
  211. IF ch # "0" THEN RETURN FALSE END
  212. ELSIF (ch # ".") & (ch # "E") & (ch # "e")
  213. & (ch # "+") & (ch # "-") THEN
  214. RETURN FALSE
  215. END;
  216. INC(i)
  217. END;
  218. RETURN seen
  219. END IsZeroReal;
  220. PROCEDURE DeclConst (name: ARRAY OF CHAR; val: ARRAY OF CHAR; t: INTEGER);
  221. VAR cls : INTEGER;
  222. init : QVal;
  223. BEGIN
  224. cls := SymTab.ClassOf(t);
  225. IF (cls = SymTab.ClStr) OR ~IsImm(val) THEN
  226. DeclVar(name, t); RETURN
  227. END;
  228. IF cls = SymTab.ClReal THEN
  229. IF IsZeroReal(val) THEN DataLine(name, TRUE, "0")
  230. ELSE
  231. DataLine(name, TRUE, "0");
  232. IF nR <= HIGH(rNames) THEN
  233. Cpy(rNames[nR], name); Cpy(rVals[nR], val); INC(nR)
  234. END
  235. END
  236. ELSE DataLine(name, FALSE, val)
  237. END
  238. END DeclConst;
  239. (* ---------------- function body ---------------- *)
  240. PROCEDURE BeginBody;
  241. VAR i : CARDINAL;
  242. t : QVal;
  243. BEGIN
  244. IF ~opened OR inBody THEN RETURN END;
  245. WL("");
  246. WL("export function w $main() {");
  247. WL("@start");
  248. inBody := TRUE;
  249. i := 0;
  250. WHILE i < nR DO
  251. NewTemp(t);
  252. W(" "); W(t); W(" =d copy "); WL(rVals[i]);
  253. StoreVar(rNames[i], t, TRUE);
  254. INC(i)
  255. END
  256. END BeginBody;
  257. PROCEDURE EndModule;
  258. BEGIN
  259. IF ~opened THEN RETURN END;
  260. IF ~inBody THEN BeginBody END;
  261. IF SymTab.Lookup("ExitCode")
  262. & (SymTab.SymKind("ExitCode") = SymTab.KindVar)
  263. & SymTab.IsIntFamily(SymTab.SymType("ExitCode")) THEN
  264. WL(" %ec =w loadw $ExitCode");
  265. WL(" ret %ec")
  266. ELSE
  267. WL(" ret 0")
  268. END;
  269. WL("}");
  270. FileIO.Close(out);
  271. opened := FALSE
  272. END EndModule;
  273. (* ---------------- temporaries, labels, jumps ---------------- *)
  274. PROCEDURE NewTemp (VAR t: QVal);
  275. BEGIN
  276. Cpy(t, "%t");
  277. AppNum(t, nTemp);
  278. INC(nTemp)
  279. END NewTemp;
  280. PROCEDURE NewLabel (VAR l: QVal);
  281. BEGIN
  282. Cpy(l, "@L");
  283. AppNum(l, nLab);
  284. INC(nLab)
  285. END NewLabel;
  286. PROCEDURE EmitLabel (l: ARRAY OF CHAR);
  287. BEGIN
  288. WL(l)
  289. END EmitLabel;
  290. PROCEDURE Jmp (l: ARRAY OF CHAR);
  291. BEGIN
  292. W(" jmp "); WL(l)
  293. END Jmp;
  294. PROCEDURE Jnz (c, t, f: ARRAY OF CHAR);
  295. BEGIN
  296. W(" jnz "); W(c); W(", "); W(t); W(", "); WL(f)
  297. END Jnz;
  298. (* ---------------- data movement and operators ---------------- *)
  299. PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal);
  300. BEGIN
  301. NewTemp(q);
  302. W(" "); W(q);
  303. IF isReal THEN W(" =d loadd $") ELSE W(" =w loadw $") END;
  304. WL(name)
  305. END LoadVar;
  306. PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN);
  307. BEGIN
  308. IF isReal THEN W(" stored ") ELSE W(" storew ") END;
  309. W(q); W(", $"); WL(name)
  310. END StoreVar;
  311. PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR;
  312. isReal: BOOLEAN);
  313. BEGIN
  314. W(" "); W(res);
  315. IF isReal THEN W(" =d ") ELSE W(" =w ") END;
  316. W(mn); W(" "); W(l); W(", "); WL(r)
  317. END Op3;
  318. PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal;
  319. isReal: BOOLEAN);
  320. VAR mn : ARRAY [0 .. 7] OF CHAR;
  321. BEGIN
  322. mn[0] := 0C;
  323. IF isReal THEN
  324. IF op = SymTab.OpEq THEN Cpy(mn, "ceqd")
  325. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cned")
  326. ELSIF op = SymTab.OpLt THEN Cpy(mn, "cltd")
  327. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cled")
  328. ELSIF op = SymTab.OpGt THEN Cpy(mn, "cgtd")
  329. ELSE Cpy(mn, "cged")
  330. END
  331. ELSE
  332. IF op = SymTab.OpEq THEN Cpy(mn, "ceqw")
  333. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cnew")
  334. ELSIF op = SymTab.OpLt THEN Cpy(mn, "csltw")
  335. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cslew")
  336. ELSIF op = SymTab.OpGt THEN Cpy(mn, "csgtw")
  337. ELSE Cpy(mn, "csgew")
  338. END
  339. END;
  340. NewTemp(q);
  341. Op3(mn, q, l, r, FALSE)
  342. END Cmp;
  343. PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  344. BEGIN
  345. NewTemp(q);
  346. IF isReal THEN Op3("sub", q, "d_0.0", a, TRUE)
  347. ELSE Op3("sub", q, "0", a, FALSE)
  348. END
  349. END NegQ;
  350. PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
  351. BEGIN
  352. NewTemp(q);
  353. Op3("xor", q, "1", a, FALSE)
  354. END NotQ;
  355. PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal);
  356. BEGIN
  357. NewTemp(q);
  358. W(" "); W(q); W(" =d swtof "); WL(a)
  359. END ConvIR;
  360. (* ---------------- loop stack and 230 guard ---------------- *)
  361. PROCEDURE PushLoop (exit: ARRAY OF CHAR);
  362. BEGIN
  363. IF loopTop <= HIGH(loopSt) THEN
  364. Cpy(loopSt[loopTop], exit); INC(loopTop)
  365. END
  366. END PushLoop;
  367. PROCEDURE PopLoop;
  368. BEGIN
  369. IF loopTop > 0 THEN DEC(loopTop) END
  370. END PopLoop;
  371. PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;
  372. BEGIN
  373. IF loopTop = 0 THEN RETURN FALSE END;
  374. Cpy(exit, loopSt[loopTop - 1]);
  375. RETURN TRUE
  376. END TopLoop;
  377. PROCEDURE NoQbeEnter;
  378. BEGIN
  379. INC(noqbe)
  380. END NoQbeEnter;
  381. PROCEDURE NoQbeExit;
  382. BEGIN
  383. IF noqbe > 0 THEN DEC(noqbe) END
  384. END NoQbeExit;
  385. PROCEDURE NoQbe (): BOOLEAN;
  386. BEGIN
  387. RETURN noqbe > 0
  388. END NoQbe;
  389. PROCEDURE Remark (s: ARRAY OF CHAR);
  390. BEGIN
  391. W("# "); WL(s)
  392. END Remark;
  393. BEGIN
  394. opened := FALSE;
  395. inBody := FALSE;
  396. nTemp := 0; nLab := 0; loopTop := 0; noqbe := 0; nR := 0
  397. END QbeGen.