emit.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. #include "all.h"
  2. enum {
  3. Ki = -1, /* matches Kw and Kl */
  4. Ka = -2, /* matches all classes */
  5. };
  6. static struct {
  7. short op;
  8. short cls;
  9. char *fmt;
  10. } omap[] = {
  11. { Oadd, Ki, "add%k %=, %0, %1" },
  12. { Oadd, Ka, "fadd.%k %=, %0, %1" },
  13. { Osub, Ki, "sub%k %=, %0, %1" },
  14. { Osub, Ka, "fsub.%k %=, %0, %1" },
  15. { Oneg, Ki, "neg%k %=, %0" },
  16. { Oneg, Ka, "fneg.%k %=, %0" },
  17. { Odiv, Ki, "div%k %=, %0, %1" },
  18. { Odiv, Ka, "fdiv.%k %=, %0, %1" },
  19. { Orem, Ki, "rem%k %=, %0, %1" },
  20. { Orem, Kl, "rem %=, %0, %1" },
  21. { Oudiv, Ki, "divu%k %=, %0, %1" },
  22. { Ourem, Ki, "remu%k %=, %0, %1" },
  23. { Omul, Ki, "mul%k %=, %0, %1" },
  24. { Omul, Ka, "fmul.%k %=, %0, %1" },
  25. { Oand, Ki, "and %=, %0, %1" },
  26. { Oor, Ki, "or %=, %0, %1" },
  27. { Oxor, Ki, "xor %=, %0, %1" },
  28. { Osar, Ki, "sra%k %=, %0, %1" },
  29. { Oshr, Ki, "srl%k %=, %0, %1" },
  30. { Oshl, Ki, "sll%k %=, %0, %1" },
  31. { Ocsltl, Ki, "slt %=, %0, %1" },
  32. { Ocultl, Ki, "sltu %=, %0, %1" },
  33. { Oceqs, Ki, "feq.s %=, %0, %1" },
  34. { Ocges, Ki, "fge.s %=, %0, %1" },
  35. { Ocgts, Ki, "fgt.s %=, %0, %1" },
  36. { Ocles, Ki, "fle.s %=, %0, %1" },
  37. { Oclts, Ki, "flt.s %=, %0, %1" },
  38. { Oceqd, Ki, "feq.d %=, %0, %1" },
  39. { Ocged, Ki, "fge.d %=, %0, %1" },
  40. { Ocgtd, Ki, "fgt.d %=, %0, %1" },
  41. { Ocled, Ki, "fle.d %=, %0, %1" },
  42. { Ocltd, Ki, "flt.d %=, %0, %1" },
  43. { Ostoreb, Kw, "sb %0, %M1" },
  44. { Ostoreh, Kw, "sh %0, %M1" },
  45. { Ostorew, Kw, "sw %0, %M1" },
  46. { Ostorel, Ki, "sd %0, %M1" },
  47. { Ostores, Kw, "fsw %0, %M1" },
  48. { Ostored, Kw, "fsd %0, %M1" },
  49. { Oloadsb, Ki, "lb %=, %M0" },
  50. { Oloadub, Ki, "lbu %=, %M0" },
  51. { Oloadsh, Ki, "lh %=, %M0" },
  52. { Oloaduh, Ki, "lhu %=, %M0" },
  53. { Oloadsw, Ki, "lw %=, %M0" },
  54. /* riscv64 always sign-extends 32-bit
  55. * values stored in 64-bit registers
  56. */
  57. { Oloaduw, Kw, "lw %=, %M0" },
  58. { Oloaduw, Kl, "lwu %=, %M0" },
  59. { Oload, Kw, "lw %=, %M0" },
  60. { Oload, Kl, "ld %=, %M0" },
  61. { Oload, Ks, "flw %=, %M0" },
  62. { Oload, Kd, "fld %=, %M0" },
  63. { Oextsb, Ki, "sext.b %=, %0" },
  64. { Oextub, Ki, "zext.b %=, %0" },
  65. { Oextsh, Ki, "sext.h %=, %0" },
  66. { Oextuh, Ki, "zext.h %=, %0" },
  67. { Oextsw, Kl, "sext.w %=, %0" },
  68. { Oextuw, Kl, "zext.w %=, %0" },
  69. { Otruncd, Ks, "fcvt.s.d %=, %0" },
  70. { Oexts, Kd, "fcvt.d.s %=, %0" },
  71. { Ostosi, Kw, "fcvt.w.s %=, %0, rtz" },
  72. { Ostosi, Kl, "fcvt.l.s %=, %0, rtz" },
  73. { Ostoui, Kw, "fcvt.wu.s %=, %0, rtz" },
  74. { Ostoui, Kl, "fcvt.lu.s %=, %0, rtz" },
  75. { Odtosi, Kw, "fcvt.w.d %=, %0, rtz" },
  76. { Odtosi, Kl, "fcvt.l.d %=, %0, rtz" },
  77. { Odtoui, Kw, "fcvt.wu.d %=, %0, rtz" },
  78. { Odtoui, Kl, "fcvt.lu.d %=, %0, rtz" },
  79. { Oswtof, Ka, "fcvt.%k.w %=, %0" },
  80. { Ouwtof, Ka, "fcvt.%k.wu %=, %0" },
  81. { Osltof, Ka, "fcvt.%k.l %=, %0" },
  82. { Oultof, Ka, "fcvt.%k.lu %=, %0" },
  83. { Ocast, Kw, "fmv.x.w %=, %0" },
  84. { Ocast, Kl, "fmv.x.d %=, %0" },
  85. { Ocast, Ks, "fmv.w.x %=, %0" },
  86. { Ocast, Kd, "fmv.d.x %=, %0" },
  87. { Ocopy, Ki, "mv %=, %0" },
  88. { Ocopy, Ka, "fmv.%k %=, %0" },
  89. { Oswap, Ki, "mv %?, %0\n\tmv %0, %1\n\tmv %1, %?" },
  90. { Oswap, Ka, "fmv.%k %?, %0\n\tfmv.%k %0, %1\n\tfmv.%k %1, %?" },
  91. { Oreqz, Ki, "seqz %=, %0" },
  92. { Ornez, Ki, "snez %=, %0" },
  93. { Ocall, Kw, "jalr %0" },
  94. { NOp, 0, 0 }
  95. };
  96. static char *rname[] = {
  97. [FP] = "fp",
  98. [SP] = "sp",
  99. [GP] = "gp",
  100. [TP] = "tp",
  101. [RA] = "ra",
  102. [T0] = "t0", "t1", "t2", "t3", "t4", "t5",
  103. [A0] = "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
  104. [S1] = "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8",
  105. "s9", "s10", "s11",
  106. [FT0] = "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
  107. "ft8", "ft9", "ft10",
  108. [FA0] = "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7",
  109. [FS0] = "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
  110. "fs8", "fs9", "fs10", "fs11",
  111. [T6] = "t6",
  112. [FT11] = "ft11",
  113. };
  114. static int64_t
  115. slot(Ref r, Fn *fn)
  116. {
  117. int s;
  118. s = rsval(r);
  119. assert(s <= fn->slot);
  120. if (s < 0)
  121. return 8 * -s;
  122. else
  123. return -4 * (fn->slot - s);
  124. }
  125. static void
  126. emitaddr(Con *c, FILE *f)
  127. {
  128. assert(c->sym.type == SGlo);
  129. fputs(str(c->sym.id), f);
  130. if (c->bits.i)
  131. fprintf(f, "+%"PRIi64, c->bits.i);
  132. }
  133. static void
  134. emitf(char *s, Ins *i, Fn *fn, FILE *f)
  135. {
  136. static char clschr[] = {'w', 'l', 's', 'd'};
  137. Ref r;
  138. int k, c;
  139. Con *pc;
  140. int64_t offset;
  141. fputc('\t', f);
  142. for (;;) {
  143. k = i->cls;
  144. while ((c = *s++) != '%')
  145. if (!c) {
  146. fputc('\n', f);
  147. return;
  148. } else
  149. fputc(c, f);
  150. switch ((c = *s++)) {
  151. default:
  152. die("invalid escape");
  153. case '?':
  154. if (KBASE(k) == 0)
  155. fputs("t6", f);
  156. else
  157. fputs("ft11", f);
  158. break;
  159. case 'k':
  160. if (i->cls != Kl)
  161. fputc(clschr[i->cls], f);
  162. break;
  163. case '=':
  164. case '0':
  165. r = c == '=' ? i->to : i->arg[0];
  166. assert(isreg(r));
  167. fputs(rname[r.val], f);
  168. break;
  169. case '1':
  170. r = i->arg[1];
  171. switch (rtype(r)) {
  172. default:
  173. die("invalid second argument");
  174. case RTmp:
  175. assert(isreg(r));
  176. fputs(rname[r.val], f);
  177. break;
  178. case RCon:
  179. pc = &fn->con[r.val];
  180. assert(pc->type == CBits);
  181. assert(pc->bits.i >= -2048 && pc->bits.i < 2048);
  182. fprintf(f, "%d", (int)pc->bits.i);
  183. break;
  184. }
  185. break;
  186. case 'M':
  187. c = *s++;
  188. assert(c == '0' || c == '1');
  189. r = i->arg[c - '0'];
  190. switch (rtype(r)) {
  191. default:
  192. die("invalid address argument");
  193. case RTmp:
  194. fprintf(f, "0(%s)", rname[r.val]);
  195. break;
  196. case RCon:
  197. pc = &fn->con[r.val];
  198. assert(pc->type == CAddr);
  199. emitaddr(pc, f);
  200. if (isstore(i->op)
  201. || (isload(i->op) && KBASE(i->cls) == 1)) {
  202. /* store (and float load)
  203. * pseudo-instructions need a
  204. * temporary register in which to
  205. * load the address
  206. */
  207. fprintf(f, ", t6");
  208. }
  209. break;
  210. case RSlot:
  211. offset = slot(r, fn);
  212. assert(offset >= -2048 && offset <= 2047);
  213. fprintf(f, "%d(fp)", (int)offset);
  214. break;
  215. }
  216. break;
  217. }
  218. }
  219. }
  220. static void
  221. loadaddr(Con *c, char *rn, FILE *f)
  222. {
  223. char off[32];
  224. if (c->sym.type == SThr) {
  225. if (c->bits.i)
  226. sprintf(off, "+%"PRIi64, c->bits.i);
  227. else
  228. off[0] = 0;
  229. fprintf(f, "\tlui %s, %%tprel_hi(%s)%s\n",
  230. rn, str(c->sym.id), off);
  231. fprintf(f, "\tadd %s, %s, tp, %%tprel_add(%s)%s\n",
  232. rn, rn, str(c->sym.id), off);
  233. fprintf(f, "\taddi %s, %s, %%tprel_lo(%s)%s\n",
  234. rn, rn, str(c->sym.id), off);
  235. } else {
  236. fprintf(f, "\tla %s, ", rn);
  237. emitaddr(c, f);
  238. fputc('\n', f);
  239. }
  240. }
  241. static void
  242. loadcon(Con *c, int r, int k, FILE *f)
  243. {
  244. char *rn;
  245. int64_t n;
  246. rn = rname[r];
  247. switch (c->type) {
  248. case CAddr:
  249. loadaddr(c, rn, f);
  250. break;
  251. case CBits:
  252. n = c->bits.i;
  253. if (!KWIDE(k))
  254. n = (int32_t)n;
  255. fprintf(f, "\tli %s, %"PRIi64"\n", rn, n);
  256. break;
  257. default:
  258. die("invalid constant");
  259. }
  260. }
  261. static void
  262. fixmem(Ref *pr, Fn *fn, FILE *f)
  263. {
  264. Ref r;
  265. int64_t s;
  266. Con *c;
  267. r = *pr;
  268. if (rtype(r) == RCon) {
  269. c = &fn->con[r.val];
  270. if (c->type == CAddr)
  271. if (c->sym.type == SThr) {
  272. loadcon(c, T6, Kl, f);
  273. *pr = TMP(T6);
  274. }
  275. }
  276. if (rtype(r) == RSlot) {
  277. s = slot(r, fn);
  278. if (s < -2048 || s > 2047) {
  279. fprintf(f, "\tli t6, %"PRId64"\n", s);
  280. fprintf(f, "\tadd t6, fp, t6\n");
  281. *pr = TMP(T6);
  282. }
  283. }
  284. }
  285. static void
  286. emitins(Ins *i, Fn *fn, FILE *f)
  287. {
  288. int o;
  289. char *rn;
  290. int64_t s;
  291. Con *con;
  292. switch (i->op) {
  293. default:
  294. if (isload(i->op))
  295. fixmem(&i->arg[0], fn, f);
  296. else if (isstore(i->op))
  297. fixmem(&i->arg[1], fn, f);
  298. Table:
  299. /* most instructions are just pulled out of
  300. * the table omap[], some special cases are
  301. * detailed below */
  302. for (o=0;; o++) {
  303. /* this linear search should really be a binary
  304. * search */
  305. if (omap[o].op == NOp)
  306. die("no match for %s(%c)",
  307. optab[i->op].name, "wlsd"[i->cls]);
  308. if (omap[o].op == i->op)
  309. if (omap[o].cls == i->cls || omap[o].cls == Ka
  310. || (omap[o].cls == Ki && KBASE(i->cls) == 0))
  311. break;
  312. }
  313. emitf(omap[o].fmt, i, fn, f);
  314. break;
  315. case Ocopy:
  316. if (req(i->to, i->arg[0]))
  317. break;
  318. if (rtype(i->to) == RSlot) {
  319. switch (rtype(i->arg[0])) {
  320. case RSlot:
  321. case RCon:
  322. die("unimplemented");
  323. break;
  324. default:
  325. assert(isreg(i->arg[0]));
  326. i->arg[1] = i->to;
  327. i->to = R;
  328. switch (i->cls) {
  329. case Kw: i->op = Ostorew; break;
  330. case Kl: i->op = Ostorel; break;
  331. case Ks: i->op = Ostores; break;
  332. case Kd: i->op = Ostored; break;
  333. }
  334. fixmem(&i->arg[1], fn, f);
  335. goto Table;
  336. }
  337. break;
  338. }
  339. assert(isreg(i->to));
  340. switch (rtype(i->arg[0])) {
  341. case RCon:
  342. loadcon(&fn->con[i->arg[0].val], i->to.val, i->cls, f);
  343. break;
  344. case RSlot:
  345. i->op = Oload;
  346. fixmem(&i->arg[0], fn, f);
  347. goto Table;
  348. default:
  349. assert(isreg(i->arg[0]));
  350. goto Table;
  351. }
  352. break;
  353. case Onop:
  354. break;
  355. case Oaddr:
  356. assert(rtype(i->arg[0]) == RSlot);
  357. rn = rname[i->to.val];
  358. s = slot(i->arg[0], fn);
  359. if (-s < 2048) {
  360. fprintf(f, "\tadd %s, fp, %"PRId64"\n", rn, s);
  361. } else {
  362. fprintf(f,
  363. "\tli %s, %"PRId64"\n"
  364. "\tadd %s, fp, %s\n",
  365. rn, s, rn, rn
  366. );
  367. }
  368. break;
  369. case Ocall:
  370. switch (rtype(i->arg[0])) {
  371. case RCon:
  372. con = &fn->con[i->arg[0].val];
  373. if (con->type != CAddr
  374. || con->sym.type != SGlo
  375. || con->bits.i)
  376. goto Invalid;
  377. fprintf(f, "\tcall %s\n", str(con->sym.id));
  378. break;
  379. case RTmp:
  380. emitf("jalr %0", i, fn, f);
  381. break;
  382. default:
  383. Invalid:
  384. die("invalid call argument");
  385. }
  386. break;
  387. case Osalloc:
  388. emitf("sub sp, sp, %0", i, fn, f);
  389. if (!req(i->to, R))
  390. emitf("mv %=, sp", i, fn, f);
  391. break;
  392. case Odbgloc:
  393. emitdbgloc(i->arg[0].val, i->arg[1].val, f);
  394. break;
  395. }
  396. }
  397. /*
  398. Stack-frame layout:
  399. +=============+
  400. | varargs |
  401. | save area |
  402. +-------------+
  403. | saved ra |
  404. | saved fp |
  405. +-------------+ <- fp
  406. | ... |
  407. | spill slots |
  408. | ... |
  409. +-------------+
  410. | ... |
  411. | locals |
  412. | ... |
  413. +-------------+
  414. | padding |
  415. +-------------+
  416. | callee-save |
  417. | registers |
  418. +=============+
  419. */
  420. void
  421. rv64_emitfn(Fn *fn, FILE *f)
  422. {
  423. static int id0;
  424. int lbl, neg, off, frame, *pr, r;
  425. Blk *b, *s;
  426. Ins *i;
  427. emitfnlnk(fn->name, &fn->lnk, f);
  428. if (fn->vararg) {
  429. /* TODO: only need space for registers
  430. * unused by named arguments
  431. */
  432. fprintf(f, "\tadd sp, sp, -64\n");
  433. for (r=A0; r<=A7; r++)
  434. fprintf(f,
  435. "\tsd %s, %d(sp)\n",
  436. rname[r], 8 * (r - A0)
  437. );
  438. }
  439. fprintf(f, "\tsd fp, -16(sp)\n");
  440. fprintf(f, "\tsd ra, -8(sp)\n");
  441. fprintf(f, "\tadd fp, sp, -16\n");
  442. frame = (16 + 4 * fn->slot + 15) & ~15;
  443. for (pr=rv64_rclob; *pr>=0; pr++) {
  444. if (fn->reg & BIT(*pr))
  445. frame += 8;
  446. }
  447. frame = (frame + 15) & ~15;
  448. if (frame <= 2048)
  449. fprintf(f,
  450. "\tadd sp, sp, -%d\n",
  451. frame
  452. );
  453. else
  454. fprintf(f,
  455. "\tli t6, %d\n"
  456. "\tsub sp, sp, t6\n",
  457. frame
  458. );
  459. for (pr=rv64_rclob, off=0; *pr>=0; pr++) {
  460. if (fn->reg & BIT(*pr)) {
  461. fprintf(f,
  462. "\t%s %s, %d(sp)\n",
  463. *pr < FT0 ? "sd" : "fsd",
  464. rname[*pr], off
  465. );
  466. off += 8;
  467. }
  468. }
  469. for (lbl=0, b=fn->start; b; b=b->link) {
  470. if (lbl || b->npred > 1)
  471. fprintf(f, ".L%d:\n", id0+b->id);
  472. for (i=b->ins; i!=&b->ins[b->nins]; i++)
  473. emitins(i, fn, f);
  474. lbl = 1;
  475. switch (b->jmp.type) {
  476. case Jhlt:
  477. fprintf(f, "\tebreak\n");
  478. break;
  479. case Jret0:
  480. if (fn->dynalloc) {
  481. if (frame - 16 <= 2048)
  482. fprintf(f,
  483. "\tadd sp, fp, -%d\n",
  484. frame - 16
  485. );
  486. else
  487. fprintf(f,
  488. "\tli t6, %d\n"
  489. "\tsub sp, fp, t6\n",
  490. frame - 16
  491. );
  492. }
  493. for (pr=rv64_rclob, off=0; *pr>=0; pr++) {
  494. if (fn->reg & BIT(*pr)) {
  495. fprintf(f,
  496. "\t%s %s, %d(sp)\n",
  497. *pr < FT0 ? "ld" : "fld",
  498. rname[*pr], off
  499. );
  500. off += 8;
  501. }
  502. }
  503. fprintf(f,
  504. "\tadd sp, fp, %d\n"
  505. "\tld ra, 8(fp)\n"
  506. "\tld fp, 0(fp)\n"
  507. "\tret\n",
  508. 16 + fn->vararg * 64
  509. );
  510. break;
  511. case Jjmp:
  512. Jmp:
  513. if (b->s1 != b->link)
  514. fprintf(f, "\tj .L%d\n", id0+b->s1->id);
  515. else
  516. lbl = 0;
  517. break;
  518. case Jjnz:
  519. neg = 0;
  520. if (b->link == b->s2) {
  521. s = b->s1;
  522. b->s1 = b->s2;
  523. b->s2 = s;
  524. neg = 1;
  525. }
  526. assert(isreg(b->jmp.arg));
  527. fprintf(f,
  528. "\tb%sz %s, .L%d\n",
  529. neg ? "ne" : "eq",
  530. rname[b->jmp.arg.val],
  531. id0+b->s2->id
  532. );
  533. goto Jmp;
  534. }
  535. }
  536. id0 += fn->nblk;
  537. elf_emitfnfin(fn->name, f);
  538. }