3 /* the risc-v lp64d abi */
5 typedef struct Class Class
;
6 typedef struct Insl Insl
;
7 typedef struct Params Params
;
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 */
14 Cfpint
= 8, /* float passed like integer */
23 char ngp
; /* only valid after typclass() */
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)
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)
54 rv64_retregs(Ref r
, int p
[2])
59 assert(rtype(r
) == RCall
);
61 nfp
= (r
.val
>> 2) & 3;
75 rv64_argregs(Ref r
, int p
[2])
80 assert(rtype(r
) == RCall
);
81 ngp
= (r
.val
>> 4) & 15;
82 nfp
= (r
.val
>> 8) & 15;
83 t5
= (r
.val
>> 12) & 1;
93 return b
| ((bits
)t5
<< T5
);
97 fpstruct(Typ
*t
, int off
, Class
*c
)
105 for (f
=*t
->fields
; f
->type
!= FEnd
; f
++)
108 else if (f
->type
== FTyp
) {
109 if (fpstruct(&typ
[f
->len
], off
, c
) == -1)
117 default: die("unreachable");
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;
133 typclass(Class
*c
, Typ
*t
, int fpabi
, int *gp
, int *fp
)
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
156 else if (!fpabi
|| fpstruct(t
, 0, c
) <= 0) {
157 for (n
=0; 8*n
<t
->size
; n
++) {
165 c
->nreg
= c
->nfp
+ c
->ngp
;
166 for (i
=0; i
<c
->nreg
; i
++)
167 if (KBASE(c
->cls
[i
]) == 0)
174 sttmps(Ref tmp
[], int ntmp
, Class
*c
, Ref mem
, Fn
*fn
)
177 [Kw
] = Ostorew
, [Kl
] = Ostorel
,
178 [Ks
] = Ostores
, [Kd
] = Ostored
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
));
194 ldregs(Class
*c
, Ref mem
, Fn
*fn
)
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
));
207 selret(Blk
*b
, Fn
*fn
)
215 if (!isret(j
) || j
== Jret0
)
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
);
230 cty
= (cr
.nfp
<< 2) | cr
.ngp
;
235 emit(Ocopy
, k
, TMP(A0
), r
, R
);
238 emit(Ocopy
, k
, TMP(FA0
), r
, R
);
243 b
->jmp
.arg
= CALL(cty
);
247 argsclass(Ins
*i0
, Ins
*i1
, Class
*carg
, int retptr
)
249 int ngp
, nfp
, *gp
, *fp
, vararg
, envc
;
264 for (i
=i0
, c
=carg
; i
<i1
; i
++, c
++) {
269 if (!vararg
&& KBASE(i
->cls
) == 1 && nfp
> 0) {
272 } else if (ngp
> 0) {
273 if (KBASE(i
->cls
) == 1)
285 t
= &typ
[i
->arg
[0].val
];
286 typclass(c
, t
, 1, gp
, fp
);
288 if (c
->nfp
>= nfp
|| c
->ngp
>= ngp
)
289 typclass(c
, t
, 0, gp
, fp
);
290 assert(c
->nfp
<= nfp
);
296 } else if (ngp
> 0) {
298 assert(c
->class == 0);
318 return envc
<< 12 | (gp
-gpreg
) << 4 | (fp
-fpreg
) << 8;
322 stkblob(Ref r
, Typ
*t
, Fn
*fn
, Insl
**ilp
)
328 il
= alloc(sizeof *il
);
329 al
= t
->align
- 2; /* specific to NAlign == 3 */
332 sz
= (t
->size
+ 7) & ~7;
333 il
->i
= (Ins
){Oalloc
+al
, Kl
, r
, {getcon(sz
, fn
)}};
339 selcall(Fn
*fn
, Ins
*i0
, Ins
*i1
, Insl
**ilp
)
345 Ref r
, r1
, r2
, tmp
[2];
347 ca
= alloc((i1
-i0
) * sizeof ca
[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
);
355 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
358 if (c
->class & Cptr
) {
359 i
->arg
[0] = newtmp("abi", Kl
, fn
);
360 stkblob(i
->arg
[0], c
->type
, fn
, ilp
);
363 if (c
->class & Cstk1
)
365 if (c
->class & Cstk2
)
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
;
376 /* spill & rega expect calls to be
377 * followed by copies from regs,
380 emit(Ocopy
, Kw
, R
, TMP(A0
), R
);
382 sttmps(tmp
, cr
.nreg
, &cr
, i1
->to
, fn
);
383 for (j
=0; j
<cr
.nreg
; 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
);
392 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(FA0
), R
);
396 emit(Ocall
, 0, R
, i1
->arg
[0], CALL(cty
));
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
)
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
);
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]);
432 /* populate the stack */
434 r
= newtmp("abi", Kl
, fn
);
435 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
436 if (i
->op
== Oargv
|| !(c
->class & Cstk
))
439 r1
= newtmp("abi", Kl
, fn
);
440 emit(Ostorew
+i
->cls
, Kw
, R
, i
->arg
[0], r1
);
442 /* TODO: we only need this sign
443 * extension for l temps passed
445 * (see rv64/isel.c:fixarg)
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
));
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
);
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
));
475 emit(Osalloc
, Kl
, r
, getcon(stk
, fn
), R
);
479 selpar(Fn
*fn
, Ins
*i0
, Ins
*i1
)
484 int j
, k
, s
, cty
, nt
;
487 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
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);
504 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
505 if (c
->class & Cfpint
) {
508 *c
->cls
= KWIDE(k
) ? Kl
: Kw
;
509 i
->to
= newtmp("abi", k
, fn
);
510 emit(Ocast
, k
, r
, i
->to
, R
);
513 if (!(c
->class & Cptr
))
516 if (c
->class & Cstk2
) {
522 sttmps(t
, nt
, c
, i
->to
, fn
);
523 stkblob(i
->to
, c
->type
, fn
, &il
);
527 for (; il
; il
=il
->link
)
531 s
= 2 + 8*fn
->vararg
;
532 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
533 if (i
->op
== Oparc
&& !(c
->class & Cptr
)) {
535 fn
->tmp
[i
->to
.val
].slot
= -s
;
536 s
+= (c
->class & Cstk2
) ? 2 : 1;
539 for (j
=0; j
<c
->nreg
; j
++) {
541 emit(Ocopy
, c
->cls
[j
], *t
++, r
, R
);
543 if (c
->class & Cstk2
) {
544 emit(Oload
, Kl
, *t
, SLOT(-s
), R
);
547 } else if (c
->class & Cstk1
) {
548 emit(Oload
, *c
->cls
, i
->to
, SLOT(-s
), R
);
551 emit(Ocopy
, *c
->cls
, i
->to
, TMP(*c
->reg
), R
);
556 .ngp
= (cty
>> 4) & 15,
557 .nfp
= (cty
>> 8) & 15,
562 selvaarg(Fn
*fn
, Ins
*i
)
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
);
575 selvastart(Fn
*fn
, Params p
, Ref ap
)
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
);
595 for (b
=fn
->start
; b
; b
=b
->link
)
598 /* lower parameters */
599 for (b
=fn
->start
, i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
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
);
610 /* lower calls, returns, and vararg instructions */
615 b
= fn
->start
; /* do it last */
620 for (i
=&b
->ins
[b
->nins
]; i
!=b
->ins
;)
626 for (i0
=i
; i0
>b
->ins
; i0
--)
627 if (!isarg((i0
-1)->op
))
629 selcall(fn
, i0
, i
, &il
);
633 selvastart(fn
, p
, i
->arg
[0]);
643 for (; il
; il
=il
->link
)
645 b
->nins
= &insb
[NIns
] - curi
;
646 idup(&b
->ins
, curi
, b
->nins
);
647 } while (b
!= fn
->start
);
650 fprintf(stderr
, "\n> After ABI lowering:\n");