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 blit0(fn
->retr
, r
, cr
.type
->size
, fn
);
229 cty
= (cr
.nfp
<< 2) | cr
.ngp
;
234 emit(Ocopy
, k
, TMP(A0
), r
, R
);
237 emit(Ocopy
, k
, TMP(FA0
), r
, R
);
242 b
->jmp
.arg
= CALL(cty
);
246 argsclass(Ins
*i0
, Ins
*i1
, Class
*carg
, int retptr
)
248 int ngp
, nfp
, *gp
, *fp
, vararg
, envc
;
263 for (i
=i0
, c
=carg
; i
<i1
; i
++, c
++) {
268 if (!vararg
&& KBASE(i
->cls
) == 1 && nfp
> 0) {
271 } else if (ngp
> 0) {
272 if (KBASE(i
->cls
) == 1)
284 t
= &typ
[i
->arg
[0].val
];
285 typclass(c
, t
, 1, gp
, fp
);
287 if (c
->nfp
>= nfp
|| c
->ngp
>= ngp
)
288 typclass(c
, t
, 0, gp
, fp
);
289 assert(c
->nfp
<= nfp
);
295 } else if (ngp
> 0) {
297 assert(c
->class == 0);
317 return envc
<< 12 | (gp
-gpreg
) << 4 | (fp
-fpreg
) << 8;
321 stkblob(Ref r
, Typ
*t
, Fn
*fn
, Insl
**ilp
)
327 il
= alloc(sizeof *il
);
328 al
= t
->align
- 2; /* specific to NAlign == 3 */
331 sz
= (t
->size
+ 7) & ~7;
332 il
->i
= (Ins
){Oalloc
+al
, Kl
, r
, {getcon(sz
, fn
)}};
338 selcall(Fn
*fn
, Ins
*i0
, Ins
*i1
, Insl
**ilp
)
346 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
349 if (!req(i1
->arg
[1], R
))
350 typclass(&cr
, &typ
[i1
->arg
[1].val
], 1, gpreg
, fpreg
);
352 cty
= argsclass(i0
, i1
, ca
, cr
.class & Cptr
);
354 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
357 if (c
->class & Cptr
) {
358 i
->arg
[0] = newtmp("abi", Kl
, fn
);
359 stkblob(i
->arg
[0], c
->type
, fn
, ilp
);
362 if (c
->class & Cstk1
)
364 if (c
->class & Cstk2
)
369 emit(Osalloc
, Kl
, R
, getcon(-stk
, fn
), R
);
371 if (!req(i1
->arg
[1], R
)) {
372 stkblob(i1
->to
, cr
.type
, fn
, ilp
);
373 cty
|= (cr
.nfp
<< 2) | cr
.ngp
;
375 /* spill & rega expect calls to be
376 * followed by copies from regs,
379 emit(Ocopy
, Kw
, R
, TMP(A0
), R
);
381 sttmps(tmp
, cr
.nreg
, &cr
, i1
->to
, fn
);
382 for (j
=0; j
<cr
.nreg
; j
++) {
384 emit(Ocopy
, cr
.cls
[j
], tmp
[j
], r
, R
);
387 } else if (KBASE(i1
->cls
) == 0) {
388 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(A0
), R
);
391 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(FA0
), R
);
395 emit(Ocall
, 0, R
, i1
->arg
[0], CALL(cty
));
398 /* struct return argument */
399 emit(Ocopy
, Kl
, TMP(A0
), i1
->to
, R
);
401 /* move arguments into registers */
402 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
403 if (i
->op
== Oargv
|| c
->class & Cstk1
)
405 if (i
->op
== Oargc
) {
406 ldregs(c
, i
->arg
[1], fn
);
407 } else if (c
->class & Cfpint
) {
408 k
= KWIDE(*c
->cls
) ? Kl
: Kw
;
409 r
= newtmp("abi", k
, fn
);
410 emit(Ocopy
, k
, TMP(*c
->reg
), r
, R
);
413 emit(Ocopy
, *c
->cls
, TMP(*c
->reg
), i
->arg
[0], R
);
417 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
418 if (c
->class & Cfpint
) {
419 k
= KWIDE(*c
->cls
) ? Kl
: Kw
;
420 emit(Ocast
, k
, TMP(*c
->reg
), i
->arg
[0], R
);
423 blit0(i
->arg
[0], i
->arg
[1], c
->type
->size
, fn
);
429 /* populate the stack */
431 r
= newtmp("abi", Kl
, fn
);
432 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
433 if (i
->op
== Oargv
|| !(c
->class & Cstk
))
436 r1
= newtmp("abi", Kl
, fn
);
437 emit(Ostorew
+i
->cls
, Kw
, R
, i
->arg
[0], r1
);
439 /* TODO: we only need this sign
440 * extension for l temps passed
442 * (see rv64/isel.c:fixarg)
445 curi
->arg
[0] = newtmp("abi", Kl
, fn
);
446 emit(Oextsw
, Kl
, curi
->arg
[0], i
->arg
[0], R
);
448 emit(Oadd
, Kl
, r1
, r
, getcon(off
, fn
));
451 if (i
->op
== Oargc
) {
452 if (c
->class & Cstk1
) {
453 blit(r
, off
, i
->arg
[1], 0, 8, fn
);
456 if (c
->class & Cstk2
) {
457 blit(r
, off
, i
->arg
[1], 8, 8, fn
);
462 emit(Osalloc
, Kl
, r
, getcon(stk
, fn
), R
);
466 selpar(Fn
*fn
, Ins
*i0
, Ins
*i1
)
471 int j
, k
, s
, cty
, nt
;
474 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
478 if (fn
->retty
>= 0) {
479 typclass(&cr
, &typ
[fn
->retty
], 1, gpreg
, fpreg
);
480 if (cr
.class & Cptr
) {
481 fn
->retr
= newtmp("abi", Kl
, fn
);
482 emit(Ocopy
, Kl
, fn
->retr
, TMP(A0
), R
);
486 cty
= argsclass(i0
, i1
, ca
, cr
.class & Cptr
);
487 fn
->reg
= rv64_argregs(CALL(cty
), 0);
491 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
492 if (c
->class & Cfpint
) {
495 *c
->cls
= KWIDE(k
) ? Kl
: Kw
;
496 i
->to
= newtmp("abi", k
, fn
);
497 emit(Ocast
, k
, r
, i
->to
, R
);
500 if (!(c
->class & Cptr
))
503 if (c
->class & Cstk2
) {
509 sttmps(t
, nt
, c
, i
->to
, fn
);
510 stkblob(i
->to
, c
->type
, fn
, &il
);
514 for (; il
; il
=il
->link
)
518 s
= 2 + 8*fn
->vararg
;
519 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
520 if (i
->op
== Oparc
&& !(c
->class & Cptr
)) {
522 fn
->tmp
[i
->to
.val
].slot
= -s
;
523 s
+= (c
->class & Cstk2
) ? 2 : 1;
526 for (j
=0; j
<c
->nreg
; j
++) {
528 emit(Ocopy
, c
->cls
[j
], *t
++, r
, R
);
530 if (c
->class & Cstk2
) {
531 emit(Oload
, Kl
, *t
, SLOT(-s
), R
);
534 } else if (c
->class & Cstk1
) {
535 emit(Oload
, *c
->cls
, i
->to
, SLOT(-s
), R
);
538 emit(Ocopy
, *c
->cls
, i
->to
, TMP(*c
->reg
), R
);
543 .ngp
= (cty
>> 4) & 15,
544 .nfp
= (cty
>> 8) & 15,
549 selvaarg(Fn
*fn
, Ins
*i
)
553 loc
= newtmp("abi", Kl
, fn
);
554 newloc
= newtmp("abi", Kl
, fn
);
555 emit(Ostorel
, Kw
, R
, newloc
, i
->arg
[0]);
556 emit(Oadd
, Kl
, newloc
, loc
, getcon(8, fn
));
557 emit(Oload
, i
->cls
, i
->to
, loc
, R
);
558 emit(Oload
, Kl
, loc
, i
->arg
[0], R
);
562 selvastart(Fn
*fn
, Params p
, Ref ap
)
567 rsave
= newtmp("abi", Kl
, fn
);
568 emit(Ostorel
, Kw
, R
, rsave
, ap
);
569 s
= p
.stk
> 2 + 8 * fn
->vararg
? p
.stk
: 2 + p
.ngp
;
570 emit(Oaddr
, Kl
, rsave
, SLOT(-s
), R
);
582 for (b
=fn
->start
; b
; b
=b
->link
)
585 /* lower parameters */
586 for (b
=fn
->start
, i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
589 p
= selpar(fn
, b
->ins
, i
);
590 n
= b
->nins
- (i
- b
->ins
) + (&insb
[NIns
] - curi
);
591 i0
= alloc(n
* sizeof(Ins
));
592 ip
= icpy(ip
= i0
, curi
, &insb
[NIns
] - curi
);
593 ip
= icpy(ip
, i
, &b
->ins
[b
->nins
] - i
);
597 /* lower calls, returns, and vararg instructions */
602 b
= fn
->start
; /* do it last */
607 for (i
=&b
->ins
[b
->nins
]; i
!=b
->ins
;)
613 for (i0
=i
; i0
>b
->ins
; i0
--)
614 if (!isarg((i0
-1)->op
))
616 selcall(fn
, i0
, i
, &il
);
620 selvastart(fn
, p
, i
->arg
[0]);
630 for (; il
; il
=il
->link
)
632 b
->nins
= &insb
[NIns
] - curi
;
633 idup(&b
->ins
, curi
, b
->nins
);
634 } while (b
!= fn
->start
);
637 fprintf(stderr
, "\n> After ABI lowering:\n");