fix unintended assignment
[qbe.git] / rv64 / abi.c
blobe31425cbc67fd9e9647bb9f17482eda3989b4aeb
1 #include "all.h"
3 /* the risc-v lp64d abi */
5 typedef struct Class Class;
6 typedef struct Insl Insl;
7 typedef struct Params Params;
9 enum {
10 Cptr = 1, /* replaced by a pointer */
11 Cstk1 = 2, /* pass first XLEN on the stack */
12 Cstk2 = 4, /* pass second XLEN on the stack */
13 Cstk = Cstk1 | Cstk2,
14 Cfpint = 8, /* float passed like integer */
17 struct Class {
18 char class;
19 Typ *type;
20 int reg[2];
21 int cls[2];
22 int off[2];
23 char ngp; /* only valid after typclass() */
24 char nfp; /* ditto */
25 char nreg;
28 struct Insl {
29 Ins i;
30 Insl *link;
33 struct Params {
34 int ngp;
35 int nfp;
36 int stk; /* stack offset for varargs */
39 static int gpreg[10] = {A0, A1, A2, A3, A4, A5, A6, A7};
40 static int fpreg[10] = {FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7};
42 /* layout of call's second argument (RCall)
44 * 29 12 8 4 2 0
45 * |0.00|x|xxxx|xxxx|xx|xx| range
46 * | | | | ` gp regs returned (0..2)
47 * | | | ` fp regs returned (0..2)
48 * | | ` gp regs passed (0..8)
49 * | ` fp regs passed (0..8)
50 * ` env pointer passed in t5 (0..1)
53 bits
54 rv64_retregs(Ref r, int p[2])
56 bits b;
57 int ngp, nfp;
59 assert(rtype(r) == RCall);
60 ngp = r.val & 3;
61 nfp = (r.val >> 2) & 3;
62 if (p) {
63 p[0] = ngp;
64 p[1] = nfp;
66 b = 0;
67 while (ngp--)
68 b |= BIT(A0+ngp);
69 while (nfp--)
70 b |= BIT(FA0+nfp);
71 return b;
74 bits
75 rv64_argregs(Ref r, int p[2])
77 bits b;
78 int ngp, nfp, t5;
80 assert(rtype(r) == RCall);
81 ngp = (r.val >> 4) & 15;
82 nfp = (r.val >> 8) & 15;
83 t5 = (r.val >> 12) & 1;
84 if (p) {
85 p[0] = ngp + t5;
86 p[1] = nfp;
88 b = 0;
89 while (ngp--)
90 b |= BIT(A0+ngp);
91 while (nfp--)
92 b |= BIT(FA0+nfp);
93 return b | ((bits)t5 << T5);
96 static int
97 fpstruct(Typ *t, int off, Class *c)
99 Field *f;
100 int n;
102 if (t->isunion)
103 return -1;
105 for (f=*t->fields; f->type != FEnd; f++)
106 if (f->type == FPad)
107 off += f->len;
108 else if (f->type == FTyp) {
109 if (fpstruct(&typ[f->len], off, c) == -1)
110 return -1;
112 else {
113 n = c->nfp + c->ngp;
114 if (n == 2)
115 return -1;
116 switch (f->type) {
117 default: die("unreachable");
118 case Fb:
119 case Fh:
120 case Fw: c->cls[n] = Kw; c->ngp++; break;
121 case Fl: c->cls[n] = Kl; c->ngp++; break;
122 case Fs: c->cls[n] = Ks; c->nfp++; break;
123 case Fd: c->cls[n] = Kd; c->nfp++; break;
125 c->off[n] = off;
126 off += f->len;
129 return c->nfp;
132 static void
133 typclass(Class *c, Typ *t, int fpabi, int *gp, int *fp)
135 uint n;
136 int i;
138 c->type = t;
139 c->class = 0;
140 c->ngp = 0;
141 c->nfp = 0;
143 if (t->align > 4)
144 err("alignments larger than 16 are not supported");
146 if (t->isdark || t->size > 16 || t->size == 0) {
147 /* large structs are replaced by a
148 * pointer to some caller-allocated
149 * memory
151 c->class |= Cptr;
152 *c->cls = Kl;
153 *c->off = 0;
154 c->ngp = 1;
156 else if (!fpabi || fpstruct(t, 0, c) <= 0) {
157 for (n=0; 8*n<t->size; n++) {
158 c->cls[n] = Kl;
159 c->off[n] = 8*n;
161 c->nfp = 0;
162 c->ngp = n;
165 c->nreg = c->nfp + c->ngp;
166 for (i=0; i<c->nreg; i++)
167 if (KBASE(c->cls[i]) == 0)
168 c->reg[i] = *gp++;
169 else
170 c->reg[i] = *fp++;
173 static void
174 sttmps(Ref tmp[], int ntmp, Class *c, Ref mem, Fn *fn)
176 static int st[] = {
177 [Kw] = Ostorew, [Kl] = Ostorel,
178 [Ks] = Ostores, [Kd] = Ostored
180 int i;
181 Ref r;
183 assert(ntmp > 0);
184 assert(ntmp <= 2);
185 for (i=0; i<ntmp; i++) {
186 tmp[i] = newtmp("abi", c->cls[i], fn);
187 r = newtmp("abi", Kl, fn);
188 emit(st[c->cls[i]], 0, R, tmp[i], r);
189 emit(Oadd, Kl, r, mem, getcon(c->off[i], fn));
193 static void
194 ldregs(Class *c, Ref mem, Fn *fn)
196 int i;
197 Ref r;
199 for (i=0; i<c->nreg; i++) {
200 r = newtmp("abi", Kl, fn);
201 emit(Oload, c->cls[i], TMP(c->reg[i]), r, R);
202 emit(Oadd, Kl, r, mem, getcon(c->off[i], fn));
206 static void
207 selret(Blk *b, Fn *fn)
209 int j, k, cty;
210 Ref r;
211 Class cr;
213 j = b->jmp.type;
215 if (!isret(j) || j == Jret0)
216 return;
218 r = b->jmp.arg;
219 b->jmp.type = Jret0;
221 if (j == Jretc) {
222 typclass(&cr, &typ[fn->retty], 1, gpreg, fpreg);
223 if (cr.class & Cptr) {
224 assert(rtype(fn->retr) == RTmp);
225 emit(Oblit1, 0, R, INT(cr.type->size), R);
226 emit(Oblit0, 0, R, r, fn->retr);
227 cty = 0;
228 } else {
229 ldregs(&cr, r, fn);
230 cty = (cr.nfp << 2) | cr.ngp;
232 } else {
233 k = j - Jretw;
234 if (KBASE(k) == 0) {
235 emit(Ocopy, k, TMP(A0), r, R);
236 cty = 1;
237 } else {
238 emit(Ocopy, k, TMP(FA0), r, R);
239 cty = 1 << 2;
243 b->jmp.arg = CALL(cty);
246 static int
247 argsclass(Ins *i0, Ins *i1, Class *carg, int retptr)
249 int ngp, nfp, *gp, *fp, vararg, envc;
250 Class *c;
251 Typ *t;
252 Ins *i;
254 gp = gpreg;
255 fp = fpreg;
256 ngp = 8;
257 nfp = 8;
258 vararg = 0;
259 envc = 0;
260 if (retptr) {
261 gp++;
262 ngp--;
264 for (i=i0, c=carg; i<i1; i++, c++) {
265 switch (i->op) {
266 case Opar:
267 case Oarg:
268 *c->cls = i->cls;
269 if (!vararg && KBASE(i->cls) == 1 && nfp > 0) {
270 nfp--;
271 *c->reg = *fp++;
272 } else if (ngp > 0) {
273 if (KBASE(i->cls) == 1)
274 c->class |= Cfpint;
275 ngp--;
276 *c->reg = *gp++;
277 } else
278 c->class |= Cstk1;
279 break;
280 case Oargv:
281 vararg = 1;
282 break;
283 case Oparc:
284 case Oargc:
285 t = &typ[i->arg[0].val];
286 typclass(c, t, 1, gp, fp);
287 if (c->nfp > 0)
288 if (c->nfp >= nfp || c->ngp >= ngp)
289 typclass(c, t, 0, gp, fp);
290 assert(c->nfp <= nfp);
291 if (c->ngp <= ngp) {
292 ngp -= c->ngp;
293 nfp -= c->nfp;
294 gp += c->ngp;
295 fp += c->nfp;
296 } else if (ngp > 0) {
297 assert(c->ngp == 2);
298 assert(c->class == 0);
299 c->class |= Cstk2;
300 c->nreg = 1;
301 ngp--;
302 gp++;
303 } else {
304 c->class |= Cstk1;
305 if (c->nreg > 1)
306 c->class |= Cstk2;
307 c->nreg = 0;
309 break;
310 case Opare:
311 case Oarge:
312 *c->reg = T5;
313 *c->cls = Kl;
314 envc = 1;
315 break;
318 return envc << 12 | (gp-gpreg) << 4 | (fp-fpreg) << 8;
321 static void
322 stkblob(Ref r, Typ *t, Fn *fn, Insl **ilp)
324 Insl *il;
325 int al;
326 uint64_t sz;
328 il = alloc(sizeof *il);
329 al = t->align - 2; /* specific to NAlign == 3 */
330 if (al < 0)
331 al = 0;
332 sz = (t->size + 7) & ~7;
333 il->i = (Ins){Oalloc+al, Kl, r, {getcon(sz, fn)}};
334 il->link = *ilp;
335 *ilp = il;
338 static void
339 selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
341 Ins *i;
342 Class *ca, *c, cr;
343 int j, k, cty;
344 uint64_t stk, off;
345 Ref r, r1, r2, tmp[2];
347 ca = alloc((i1-i0) * sizeof ca[0]);
348 cr.class = 0;
350 if (!req(i1->arg[1], R))
351 typclass(&cr, &typ[i1->arg[1].val], 1, gpreg, fpreg);
353 cty = argsclass(i0, i1, ca, cr.class & Cptr);
354 stk = 0;
355 for (i=i0, c=ca; i<i1; i++, c++) {
356 if (i->op == Oargv)
357 continue;
358 if (c->class & Cptr) {
359 i->arg[0] = newtmp("abi", Kl, fn);
360 stkblob(i->arg[0], c->type, fn, ilp);
361 i->op = Oarg;
363 if (c->class & Cstk1)
364 stk += 8;
365 if (c->class & Cstk2)
366 stk += 8;
368 stk += stk & 15;
369 if (stk)
370 emit(Osalloc, Kl, R, getcon(-stk, fn), R);
372 if (!req(i1->arg[1], R)) {
373 stkblob(i1->to, cr.type, fn, ilp);
374 cty |= (cr.nfp << 2) | cr.ngp;
375 if (cr.class & Cptr)
376 /* spill & rega expect calls to be
377 * followed by copies from regs,
378 * so we emit a dummy
380 emit(Ocopy, Kw, R, TMP(A0), R);
381 else {
382 sttmps(tmp, cr.nreg, &cr, i1->to, fn);
383 for (j=0; j<cr.nreg; j++) {
384 r = TMP(cr.reg[j]);
385 emit(Ocopy, cr.cls[j], tmp[j], r, R);
388 } else if (KBASE(i1->cls) == 0) {
389 emit(Ocopy, i1->cls, i1->to, TMP(A0), R);
390 cty |= 1;
391 } else {
392 emit(Ocopy, i1->cls, i1->to, TMP(FA0), R);
393 cty |= 1 << 2;
396 emit(Ocall, 0, R, i1->arg[0], CALL(cty));
398 if (cr.class & Cptr)
399 /* struct return argument */
400 emit(Ocopy, Kl, TMP(A0), i1->to, R);
402 /* move arguments into registers */
403 for (i=i0, c=ca; i<i1; i++, c++) {
404 if (i->op == Oargv || c->class & Cstk1)
405 continue;
406 if (i->op == Oargc) {
407 ldregs(c, i->arg[1], fn);
408 } else if (c->class & Cfpint) {
409 k = KWIDE(*c->cls) ? Kl : Kw;
410 r = newtmp("abi", k, fn);
411 emit(Ocopy, k, TMP(*c->reg), r, R);
412 *c->reg = r.val;
413 } else {
414 emit(Ocopy, *c->cls, TMP(*c->reg), i->arg[0], R);
418 for (i=i0, c=ca; i<i1; i++, c++) {
419 if (c->class & Cfpint) {
420 k = KWIDE(*c->cls) ? Kl : Kw;
421 emit(Ocast, k, TMP(*c->reg), i->arg[0], R);
423 if (c->class & Cptr) {
424 emit(Oblit1, 0, R, INT(c->type->size), R);
425 emit(Oblit0, 0, R, i->arg[1], i->arg[0]);
429 if (!stk)
430 return;
432 /* populate the stack */
433 off = 0;
434 r = newtmp("abi", Kl, fn);
435 for (i=i0, c=ca; i<i1; i++, c++) {
436 if (i->op == Oargv || !(c->class & Cstk))
437 continue;
438 if (i->op == Oarg) {
439 r1 = newtmp("abi", Kl, fn);
440 emit(Ostorew+i->cls, Kw, R, i->arg[0], r1);
441 if (i->cls == Kw) {
442 /* TODO: we only need this sign
443 * extension for l temps passed
444 * as w arguments
445 * (see rv64/isel.c:fixarg)
447 curi->op = Ostorel;
448 curi->arg[0] = newtmp("abi", Kl, fn);
449 emit(Oextsw, Kl, curi->arg[0], i->arg[0], R);
451 emit(Oadd, Kl, r1, r, getcon(off, fn));
452 off += 8;
454 if (i->op == Oargc) {
455 if (c->class & Cstk1) {
456 r1 = newtmp("abi", Kl, fn);
457 r2 = newtmp("abi", Kl, fn);
458 emit(Ostorel, 0, R, r2, r1);
459 emit(Oadd, Kl, r1, r, getcon(off, fn));
460 emit(Oload, Kl, r2, i->arg[1], R);
461 off += 8;
463 if (c->class & Cstk2) {
464 r1 = newtmp("abi", Kl, fn);
465 r2 = newtmp("abi", Kl, fn);
466 emit(Ostorel, 0, R, r2, r1);
467 emit(Oadd, Kl, r1, r, getcon(off, fn));
468 r1 = newtmp("abi", Kl, fn);
469 emit(Oload, Kl, r2, r1, R);
470 emit(Oadd, Kl, r1, i->arg[1], getcon(8, fn));
471 off += 8;
475 emit(Osalloc, Kl, r, getcon(stk, fn), R);
478 static Params
479 selpar(Fn *fn, Ins *i0, Ins *i1)
481 Class *ca, *c, cr;
482 Insl *il;
483 Ins *i;
484 int j, k, s, cty, nt;
485 Ref r, tmp[17], *t;
487 ca = alloc((i1-i0) * sizeof ca[0]);
488 cr.class = 0;
489 curi = &insb[NIns];
491 if (fn->retty >= 0) {
492 typclass(&cr, &typ[fn->retty], 1, gpreg, fpreg);
493 if (cr.class & Cptr) {
494 fn->retr = newtmp("abi", Kl, fn);
495 emit(Ocopy, Kl, fn->retr, TMP(A0), R);
499 cty = argsclass(i0, i1, ca, cr.class & Cptr);
500 fn->reg = rv64_argregs(CALL(cty), 0);
502 il = 0;
503 t = tmp;
504 for (i=i0, c=ca; i<i1; i++, c++) {
505 if (c->class & Cfpint) {
506 r = i->to;
507 k = *c->cls;
508 *c->cls = KWIDE(k) ? Kl : Kw;
509 i->to = newtmp("abi", k, fn);
510 emit(Ocast, k, r, i->to, R);
512 if (i->op == Oparc)
513 if (!(c->class & Cptr))
514 if (c->nreg != 0) {
515 nt = c->nreg;
516 if (c->class & Cstk2) {
517 c->cls[1] = Kl;
518 c->off[1] = 8;
519 assert(nt == 1);
520 nt = 2;
522 sttmps(t, nt, c, i->to, fn);
523 stkblob(i->to, c->type, fn, &il);
524 t += nt;
527 for (; il; il=il->link)
528 emiti(il->i);
530 t = tmp;
531 s = 2 + 8*fn->vararg;
532 for (i=i0, c=ca; i<i1; i++, c++)
533 if (i->op == Oparc && !(c->class & Cptr)) {
534 if (c->nreg == 0) {
535 fn->tmp[i->to.val].slot = -s;
536 s += (c->class & Cstk2) ? 2 : 1;
537 continue;
539 for (j=0; j<c->nreg; j++) {
540 r = TMP(c->reg[j]);
541 emit(Ocopy, c->cls[j], *t++, r, R);
543 if (c->class & Cstk2) {
544 emit(Oload, Kl, *t, SLOT(-s), R);
545 t++, s++;
547 } else if (c->class & Cstk1) {
548 emit(Oload, *c->cls, i->to, SLOT(-s), R);
549 s++;
550 } else {
551 emit(Ocopy, *c->cls, i->to, TMP(*c->reg), R);
554 return (Params){
555 .stk = s,
556 .ngp = (cty >> 4) & 15,
557 .nfp = (cty >> 8) & 15,
561 static void
562 selvaarg(Fn *fn, Ins *i)
564 Ref loc, newloc;
566 loc = newtmp("abi", Kl, fn);
567 newloc = newtmp("abi", Kl, fn);
568 emit(Ostorel, Kw, R, newloc, i->arg[0]);
569 emit(Oadd, Kl, newloc, loc, getcon(8, fn));
570 emit(Oload, i->cls, i->to, loc, R);
571 emit(Oload, Kl, loc, i->arg[0], R);
574 static void
575 selvastart(Fn *fn, Params p, Ref ap)
577 Ref rsave;
578 int s;
580 rsave = newtmp("abi", Kl, fn);
581 emit(Ostorel, Kw, R, rsave, ap);
582 s = p.stk > 2 + 8 * fn->vararg ? p.stk : 2 + p.ngp;
583 emit(Oaddr, Kl, rsave, SLOT(-s), R);
586 void
587 rv64_abi(Fn *fn)
589 Blk *b;
590 Ins *i, *i0, *ip;
591 Insl *il;
592 int n;
593 Params p;
595 for (b=fn->start; b; b=b->link)
596 b->visit = 0;
598 /* lower parameters */
599 for (b=fn->start, i=b->ins; i<&b->ins[b->nins]; i++)
600 if (!ispar(i->op))
601 break;
602 p = selpar(fn, b->ins, i);
603 n = b->nins - (i - b->ins) + (&insb[NIns] - curi);
604 i0 = alloc(n * sizeof(Ins));
605 ip = icpy(ip = i0, curi, &insb[NIns] - curi);
606 ip = icpy(ip, i, &b->ins[b->nins] - i);
607 b->nins = n;
608 b->ins = i0;
610 /* lower calls, returns, and vararg instructions */
611 il = 0;
612 b = fn->start;
613 do {
614 if (!(b = b->link))
615 b = fn->start; /* do it last */
616 if (b->visit)
617 continue;
618 curi = &insb[NIns];
619 selret(b, fn);
620 for (i=&b->ins[b->nins]; i!=b->ins;)
621 switch ((--i)->op) {
622 default:
623 emiti(*i);
624 break;
625 case Ocall:
626 for (i0=i; i0>b->ins; i0--)
627 if (!isarg((i0-1)->op))
628 break;
629 selcall(fn, i0, i, &il);
630 i = i0;
631 break;
632 case Ovastart:
633 selvastart(fn, p, i->arg[0]);
634 break;
635 case Ovaarg:
636 selvaarg(fn, i);
637 break;
638 case Oarg:
639 case Oargc:
640 die("unreachable");
642 if (b == fn->start)
643 for (; il; il=il->link)
644 emiti(il->i);
645 b->nins = &insb[NIns] - curi;
646 idup(&b->ins, curi, b->nins);
647 } while (b != fn->start);
649 if (debug['A']) {
650 fprintf(stderr, "\n> After ABI lowering:\n");
651 printfn(fn, stderr);