abi.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. #include "all.h"
  2. /* the risc-v lp64d abi */
  3. typedef struct Class Class;
  4. typedef struct Insl Insl;
  5. typedef struct Params Params;
  6. enum {
  7. Cptr = 1, /* replaced by a pointer */
  8. Cstk1 = 2, /* pass first XLEN on the stack */
  9. Cstk2 = 4, /* pass second XLEN on the stack */
  10. Cstk = Cstk1 | Cstk2,
  11. Cfpint = 8, /* float passed like integer */
  12. };
  13. struct Class {
  14. char class;
  15. Typ *type;
  16. int reg[2];
  17. int cls[2];
  18. int off[2];
  19. char ngp; /* only valid after typclass() */
  20. char nfp; /* ditto */
  21. char nreg;
  22. };
  23. struct Insl {
  24. Ins i;
  25. Insl *link;
  26. };
  27. struct Params {
  28. int ngp;
  29. int nfp;
  30. int stk; /* stack offset for varargs */
  31. };
  32. static int gpreg[10] = {A0, A1, A2, A3, A4, A5, A6, A7};
  33. static int fpreg[10] = {FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7};
  34. /* layout of call's second argument (RCall)
  35. *
  36. * 29 12 8 4 2 0
  37. * |0.00|x|xxxx|xxxx|xx|xx| range
  38. * | | | | ` gp regs returned (0..2)
  39. * | | | ` fp regs returned (0..2)
  40. * | | ` gp regs passed (0..8)
  41. * | ` fp regs passed (0..8)
  42. * ` env pointer passed in t5 (0..1)
  43. */
  44. bits
  45. rv64_retregs(Ref r, int p[2])
  46. {
  47. bits b;
  48. int ngp, nfp;
  49. assert(rtype(r) == RCall);
  50. ngp = r.val & 3;
  51. nfp = (r.val >> 2) & 3;
  52. if (p) {
  53. p[0] = ngp;
  54. p[1] = nfp;
  55. }
  56. b = 0;
  57. while (ngp--)
  58. b |= BIT(A0+ngp);
  59. while (nfp--)
  60. b |= BIT(FA0+nfp);
  61. return b;
  62. }
  63. bits
  64. rv64_argregs(Ref r, int p[2])
  65. {
  66. bits b;
  67. int ngp, nfp, t5;
  68. assert(rtype(r) == RCall);
  69. ngp = (r.val >> 4) & 15;
  70. nfp = (r.val >> 8) & 15;
  71. t5 = (r.val >> 12) & 1;
  72. if (p) {
  73. p[0] = ngp + t5;
  74. p[1] = nfp;
  75. }
  76. b = 0;
  77. while (ngp--)
  78. b |= BIT(A0+ngp);
  79. while (nfp--)
  80. b |= BIT(FA0+nfp);
  81. return b | ((bits)t5 << T5);
  82. }
  83. static int
  84. fpstruct(Typ *t, int off, Class *c)
  85. {
  86. Field *f;
  87. int n;
  88. if (t->isunion)
  89. return -1;
  90. for (f=*t->fields; f->type != FEnd; f++)
  91. if (f->type == FPad)
  92. off += f->len;
  93. else if (f->type == FTyp) {
  94. if (fpstruct(&typ[f->len], off, c) == -1)
  95. return -1;
  96. }
  97. else {
  98. n = c->nfp + c->ngp;
  99. if (n == 2)
  100. return -1;
  101. switch (f->type) {
  102. default: die("unreachable");
  103. case Fb:
  104. case Fh:
  105. case Fw: c->cls[n] = Kw; c->ngp++; break;
  106. case Fl: c->cls[n] = Kl; c->ngp++; break;
  107. case Fs: c->cls[n] = Ks; c->nfp++; break;
  108. case Fd: c->cls[n] = Kd; c->nfp++; break;
  109. }
  110. c->off[n] = off;
  111. off += f->len;
  112. }
  113. return c->nfp;
  114. }
  115. static void
  116. typclass(Class *c, Typ *t, int fpabi, int *gp, int *fp)
  117. {
  118. uint n;
  119. int i;
  120. c->type = t;
  121. c->class = 0;
  122. c->ngp = 0;
  123. c->nfp = 0;
  124. if (t->align > 4)
  125. err("alignments larger than 16 are not supported");
  126. if (t->isdark || t->size > 16 || t->size == 0) {
  127. /* large structs are replaced by a
  128. * pointer to some caller-allocated
  129. * memory
  130. */
  131. c->class |= Cptr;
  132. *c->cls = Kl;
  133. *c->off = 0;
  134. c->ngp = 1;
  135. }
  136. else if (!fpabi || fpstruct(t, 0, c) <= 0) {
  137. for (n=0; 8*n<t->size; n++) {
  138. c->cls[n] = Kl;
  139. c->off[n] = 8*n;
  140. }
  141. c->nfp = 0;
  142. c->ngp = n;
  143. }
  144. c->nreg = c->nfp + c->ngp;
  145. for (i=0; i<c->nreg; i++)
  146. if (KBASE(c->cls[i]) == 0)
  147. c->reg[i] = *gp++;
  148. else
  149. c->reg[i] = *fp++;
  150. }
  151. static void
  152. sttmps(Ref tmp[], int ntmp, Class *c, Ref mem, Fn *fn)
  153. {
  154. static int st[] = {
  155. [Kw] = Ostorew, [Kl] = Ostorel,
  156. [Ks] = Ostores, [Kd] = Ostored
  157. };
  158. int i;
  159. Ref r;
  160. assert(ntmp > 0);
  161. assert(ntmp <= 2);
  162. for (i=0; i<ntmp; i++) {
  163. tmp[i] = newtmp("abi", c->cls[i], fn);
  164. r = newtmp("abi", Kl, fn);
  165. emit(st[c->cls[i]], 0, R, tmp[i], r);
  166. emit(Oadd, Kl, r, mem, getcon(c->off[i], fn));
  167. }
  168. }
  169. static void
  170. ldregs(Class *c, Ref mem, Fn *fn)
  171. {
  172. int i;
  173. Ref r;
  174. for (i=0; i<c->nreg; i++) {
  175. r = newtmp("abi", Kl, fn);
  176. emit(Oload, c->cls[i], TMP(c->reg[i]), r, R);
  177. emit(Oadd, Kl, r, mem, getcon(c->off[i], fn));
  178. }
  179. }
  180. static void
  181. selret(Blk *b, Fn *fn)
  182. {
  183. int j, k, cty;
  184. Ref r;
  185. Class cr;
  186. j = b->jmp.type;
  187. if (!isret(j) || j == Jret0)
  188. return;
  189. r = b->jmp.arg;
  190. b->jmp.type = Jret0;
  191. if (j == Jretc) {
  192. typclass(&cr, &typ[fn->retty], 1, gpreg, fpreg);
  193. if (cr.class & Cptr) {
  194. assert(rtype(fn->retr) == RTmp);
  195. emit(Oblit1, 0, R, INT(cr.type->size), R);
  196. emit(Oblit0, 0, R, r, fn->retr);
  197. cty = 0;
  198. } else {
  199. ldregs(&cr, r, fn);
  200. cty = (cr.nfp << 2) | cr.ngp;
  201. }
  202. } else {
  203. k = j - Jretw;
  204. if (KBASE(k) == 0) {
  205. emit(Ocopy, k, TMP(A0), r, R);
  206. cty = 1;
  207. } else {
  208. emit(Ocopy, k, TMP(FA0), r, R);
  209. cty = 1 << 2;
  210. }
  211. }
  212. b->jmp.arg = CALL(cty);
  213. }
  214. static int
  215. argsclass(Ins *i0, Ins *i1, Class *carg, int retptr)
  216. {
  217. int ngp, nfp, *gp, *fp, vararg, envc;
  218. Class *c;
  219. Typ *t;
  220. Ins *i;
  221. gp = gpreg;
  222. fp = fpreg;
  223. ngp = 8;
  224. nfp = 8;
  225. vararg = 0;
  226. envc = 0;
  227. if (retptr) {
  228. gp++;
  229. ngp--;
  230. }
  231. for (i=i0, c=carg; i<i1; i++, c++) {
  232. switch (i->op) {
  233. case Opar:
  234. case Oarg:
  235. *c->cls = i->cls;
  236. if (!vararg && KBASE(i->cls) == 1 && nfp > 0) {
  237. nfp--;
  238. *c->reg = *fp++;
  239. } else if (ngp > 0) {
  240. if (KBASE(i->cls) == 1)
  241. c->class |= Cfpint;
  242. ngp--;
  243. *c->reg = *gp++;
  244. } else
  245. c->class |= Cstk1;
  246. break;
  247. case Oargv:
  248. vararg = 1;
  249. break;
  250. case Oparc:
  251. case Oargc:
  252. t = &typ[i->arg[0].val];
  253. typclass(c, t, 1, gp, fp);
  254. if (c->nfp > 0)
  255. if (c->nfp >= nfp || c->ngp >= ngp)
  256. typclass(c, t, 0, gp, fp);
  257. assert(c->nfp <= nfp);
  258. if (c->ngp <= ngp) {
  259. ngp -= c->ngp;
  260. nfp -= c->nfp;
  261. gp += c->ngp;
  262. fp += c->nfp;
  263. } else if (ngp > 0) {
  264. assert(c->ngp == 2);
  265. assert(c->class == 0);
  266. c->class |= Cstk2;
  267. c->nreg = 1;
  268. ngp--;
  269. gp++;
  270. } else {
  271. c->class |= Cstk1;
  272. if (c->nreg > 1)
  273. c->class |= Cstk2;
  274. c->nreg = 0;
  275. }
  276. break;
  277. case Opare:
  278. case Oarge:
  279. *c->reg = T5;
  280. *c->cls = Kl;
  281. envc = 1;
  282. break;
  283. }
  284. }
  285. return envc << 12 | (gp-gpreg) << 4 | (fp-fpreg) << 8;
  286. }
  287. static void
  288. stkblob(Ref r, Typ *t, Fn *fn, Insl **ilp)
  289. {
  290. Insl *il;
  291. int al;
  292. uint64_t sz;
  293. il = alloc(sizeof *il);
  294. al = t->align - 2; /* specific to NAlign == 3 */
  295. if (al < 0)
  296. al = 0;
  297. sz = (t->size + 7) & ~7;
  298. il->i = (Ins){Oalloc+al, Kl, r, {getcon(sz, fn)}};
  299. il->link = *ilp;
  300. *ilp = il;
  301. }
  302. static void
  303. selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
  304. {
  305. Ins *i;
  306. Class *ca, *c, cr;
  307. int j, k, cty;
  308. uint64_t stk, off;
  309. Ref r, r1, r2, tmp[2];
  310. ca = alloc((i1-i0) * sizeof ca[0]);
  311. cr.class = 0;
  312. if (!req(i1->arg[1], R))
  313. typclass(&cr, &typ[i1->arg[1].val], 1, gpreg, fpreg);
  314. cty = argsclass(i0, i1, ca, cr.class & Cptr);
  315. stk = 0;
  316. for (i=i0, c=ca; i<i1; i++, c++) {
  317. if (i->op == Oargv)
  318. continue;
  319. if (c->class & Cptr) {
  320. i->arg[0] = newtmp("abi", Kl, fn);
  321. stkblob(i->arg[0], c->type, fn, ilp);
  322. i->op = Oarg;
  323. }
  324. if (c->class & Cstk1)
  325. stk += 8;
  326. if (c->class & Cstk2)
  327. stk += 8;
  328. }
  329. stk += stk & 15;
  330. if (stk)
  331. emit(Osalloc, Kl, R, getcon(-stk, fn), R);
  332. if (!req(i1->arg[1], R)) {
  333. stkblob(i1->to, cr.type, fn, ilp);
  334. cty |= (cr.nfp << 2) | cr.ngp;
  335. if (cr.class & Cptr)
  336. /* spill & rega expect calls to be
  337. * followed by copies from regs,
  338. * so we emit a dummy
  339. */
  340. emit(Ocopy, Kw, R, TMP(A0), R);
  341. else {
  342. sttmps(tmp, cr.nreg, &cr, i1->to, fn);
  343. for (j=0; j<cr.nreg; j++) {
  344. r = TMP(cr.reg[j]);
  345. emit(Ocopy, cr.cls[j], tmp[j], r, R);
  346. }
  347. }
  348. } else if (KBASE(i1->cls) == 0) {
  349. emit(Ocopy, i1->cls, i1->to, TMP(A0), R);
  350. cty |= 1;
  351. } else {
  352. emit(Ocopy, i1->cls, i1->to, TMP(FA0), R);
  353. cty |= 1 << 2;
  354. }
  355. emit(Ocall, 0, R, i1->arg[0], CALL(cty));
  356. if (cr.class & Cptr)
  357. /* struct return argument */
  358. emit(Ocopy, Kl, TMP(A0), i1->to, R);
  359. /* move arguments into registers */
  360. for (i=i0, c=ca; i<i1; i++, c++) {
  361. if (i->op == Oargv || c->class & Cstk1)
  362. continue;
  363. if (i->op == Oargc) {
  364. ldregs(c, i->arg[1], fn);
  365. } else if (c->class & Cfpint) {
  366. k = KWIDE(*c->cls) ? Kl : Kw;
  367. r = newtmp("abi", k, fn);
  368. emit(Ocopy, k, TMP(*c->reg), r, R);
  369. *c->reg = r.val;
  370. } else {
  371. emit(Ocopy, *c->cls, TMP(*c->reg), i->arg[0], R);
  372. }
  373. }
  374. for (i=i0, c=ca; i<i1; i++, c++) {
  375. if (c->class & Cfpint) {
  376. k = KWIDE(*c->cls) ? Kl : Kw;
  377. emit(Ocast, k, TMP(*c->reg), i->arg[0], R);
  378. }
  379. if (c->class & Cptr) {
  380. emit(Oblit1, 0, R, INT(c->type->size), R);
  381. emit(Oblit0, 0, R, i->arg[1], i->arg[0]);
  382. }
  383. }
  384. if (!stk)
  385. return;
  386. /* populate the stack */
  387. off = 0;
  388. r = newtmp("abi", Kl, fn);
  389. for (i=i0, c=ca; i<i1; i++, c++) {
  390. if (i->op == Oargv || !(c->class & Cstk))
  391. continue;
  392. if (i->op == Oarg) {
  393. r1 = newtmp("abi", Kl, fn);
  394. emit(Ostorew+i->cls, Kw, R, i->arg[0], r1);
  395. if (i->cls == Kw) {
  396. /* TODO: we only need this sign
  397. * extension for l temps passed
  398. * as w arguments
  399. * (see rv64/isel.c:fixarg)
  400. */
  401. curi->op = Ostorel;
  402. curi->arg[0] = newtmp("abi", Kl, fn);
  403. emit(Oextsw, Kl, curi->arg[0], i->arg[0], R);
  404. }
  405. emit(Oadd, Kl, r1, r, getcon(off, fn));
  406. off += 8;
  407. }
  408. if (i->op == Oargc) {
  409. if (c->class & Cstk1) {
  410. r1 = newtmp("abi", Kl, fn);
  411. r2 = newtmp("abi", Kl, fn);
  412. emit(Ostorel, 0, R, r2, r1);
  413. emit(Oadd, Kl, r1, r, getcon(off, fn));
  414. emit(Oload, Kl, r2, i->arg[1], R);
  415. off += 8;
  416. }
  417. if (c->class & Cstk2) {
  418. r1 = newtmp("abi", Kl, fn);
  419. r2 = newtmp("abi", Kl, fn);
  420. emit(Ostorel, 0, R, r2, r1);
  421. emit(Oadd, Kl, r1, r, getcon(off, fn));
  422. r1 = newtmp("abi", Kl, fn);
  423. emit(Oload, Kl, r2, r1, R);
  424. emit(Oadd, Kl, r1, i->arg[1], getcon(8, fn));
  425. off += 8;
  426. }
  427. }
  428. }
  429. emit(Osalloc, Kl, r, getcon(stk, fn), R);
  430. }
  431. static Params
  432. selpar(Fn *fn, Ins *i0, Ins *i1)
  433. {
  434. Class *ca, *c, cr;
  435. Insl *il;
  436. Ins *i;
  437. int j, k, s, cty, nt;
  438. Ref r, tmp[17], *t;
  439. ca = alloc((i1-i0) * sizeof ca[0]);
  440. cr.class = 0;
  441. curi = &insb[NIns];
  442. if (fn->retty >= 0) {
  443. typclass(&cr, &typ[fn->retty], 1, gpreg, fpreg);
  444. if (cr.class & Cptr) {
  445. fn->retr = newtmp("abi", Kl, fn);
  446. emit(Ocopy, Kl, fn->retr, TMP(A0), R);
  447. }
  448. }
  449. cty = argsclass(i0, i1, ca, cr.class & Cptr);
  450. fn->reg = rv64_argregs(CALL(cty), 0);
  451. il = 0;
  452. t = tmp;
  453. for (i=i0, c=ca; i<i1; i++, c++) {
  454. if (c->class & Cfpint) {
  455. r = i->to;
  456. k = *c->cls;
  457. *c->cls = KWIDE(k) ? Kl : Kw;
  458. i->to = newtmp("abi", k, fn);
  459. emit(Ocast, k, r, i->to, R);
  460. }
  461. if (i->op == Oparc)
  462. if (!(c->class & Cptr))
  463. if (c->nreg != 0) {
  464. nt = c->nreg;
  465. if (c->class & Cstk2) {
  466. c->cls[1] = Kl;
  467. c->off[1] = 8;
  468. assert(nt == 1);
  469. nt = 2;
  470. }
  471. sttmps(t, nt, c, i->to, fn);
  472. stkblob(i->to, c->type, fn, &il);
  473. t += nt;
  474. }
  475. }
  476. for (; il; il=il->link)
  477. emiti(il->i);
  478. t = tmp;
  479. s = 2 + 8*fn->vararg;
  480. for (i=i0, c=ca; i<i1; i++, c++)
  481. if (i->op == Oparc && !(c->class & Cptr)) {
  482. if (c->nreg == 0) {
  483. fn->tmp[i->to.val].slot = -s;
  484. s += (c->class & Cstk2) ? 2 : 1;
  485. continue;
  486. }
  487. for (j=0; j<c->nreg; j++) {
  488. r = TMP(c->reg[j]);
  489. emit(Ocopy, c->cls[j], *t++, r, R);
  490. }
  491. if (c->class & Cstk2) {
  492. emit(Oload, Kl, *t, SLOT(-s), R);
  493. t++, s++;
  494. }
  495. } else if (c->class & Cstk1) {
  496. emit(Oload, *c->cls, i->to, SLOT(-s), R);
  497. s++;
  498. } else {
  499. emit(Ocopy, *c->cls, i->to, TMP(*c->reg), R);
  500. }
  501. return (Params){
  502. .stk = s,
  503. .ngp = (cty >> 4) & 15,
  504. .nfp = (cty >> 8) & 15,
  505. };
  506. }
  507. static void
  508. selvaarg(Fn *fn, Ins *i)
  509. {
  510. Ref loc, newloc;
  511. loc = newtmp("abi", Kl, fn);
  512. newloc = newtmp("abi", Kl, fn);
  513. emit(Ostorel, Kw, R, newloc, i->arg[0]);
  514. emit(Oadd, Kl, newloc, loc, getcon(8, fn));
  515. emit(Oload, i->cls, i->to, loc, R);
  516. emit(Oload, Kl, loc, i->arg[0], R);
  517. }
  518. static void
  519. selvastart(Fn *fn, Params p, Ref ap)
  520. {
  521. Ref rsave;
  522. int s;
  523. rsave = newtmp("abi", Kl, fn);
  524. emit(Ostorel, Kw, R, rsave, ap);
  525. s = p.stk > 2 + 8 * fn->vararg ? p.stk : 2 + p.ngp;
  526. emit(Oaddr, Kl, rsave, SLOT(-s), R);
  527. }
  528. void
  529. rv64_abi(Fn *fn)
  530. {
  531. Blk *b;
  532. Ins *i, *i0;
  533. Insl *il;
  534. int n0, n1, ioff;
  535. Params p;
  536. for (b=fn->start; b; b=b->link)
  537. b->visit = 0;
  538. /* lower parameters */
  539. for (b=fn->start, i=b->ins; i<&b->ins[b->nins]; i++)
  540. if (!ispar(i->op))
  541. break;
  542. p = selpar(fn, b->ins, i);
  543. n0 = &insb[NIns] - curi;
  544. ioff = i - b->ins;
  545. n1 = b->nins - ioff;
  546. vgrow(&b->ins, n0+n1);
  547. icpy(b->ins+n0, b->ins+ioff, n1);
  548. icpy(b->ins, curi, n0);
  549. b->nins = n0+n1;
  550. /* lower calls, returns, and vararg instructions */
  551. il = 0;
  552. b = fn->start;
  553. do {
  554. if (!(b = b->link))
  555. b = fn->start; /* do it last */
  556. if (b->visit)
  557. continue;
  558. curi = &insb[NIns];
  559. selret(b, fn);
  560. for (i=&b->ins[b->nins]; i!=b->ins;)
  561. switch ((--i)->op) {
  562. default:
  563. emiti(*i);
  564. break;
  565. case Ocall:
  566. for (i0=i; i0>b->ins; i0--)
  567. if (!isarg((i0-1)->op))
  568. break;
  569. selcall(fn, i0, i, &il);
  570. i = i0;
  571. break;
  572. case Ovastart:
  573. selvastart(fn, p, i->arg[0]);
  574. break;
  575. case Ovaarg:
  576. selvaarg(fn, i);
  577. break;
  578. case Oarg:
  579. case Oargc:
  580. die("unreachable");
  581. }
  582. if (b == fn->start)
  583. for (; il; il=il->link)
  584. emiti(il->i);
  585. idup(b, curi, &insb[NIns]-curi);
  586. } while (b != fn->start);
  587. if (debug['A']) {
  588. fprintf(stderr, "\n> After ABI lowering:\n");
  589. printfn(fn, stderr);
  590. }
  591. }