3 typedef struct Class Class
;
4 typedef struct Insl Insl
;
5 typedef struct Params Params
;
8 Cstk
= 1, /* pass on the stack */
9 Cptr
= 2, /* replaced by a pointer */
39 static int gpreg
[12] = {R0
, R1
, R2
, R3
, R4
, R5
, R6
, R7
};
40 static int fpreg
[12] = {V0
, V1
, V2
, V3
, V4
, V5
, V6
, V7
};
42 /* layout of call's second argument (RCall)
46 * |0.00|x|x|xxxx|xxxx|xxx|xx| range
47 * | | | | | ` gp regs returned (0..2)
48 * | | | | ` fp regs returned (0..4)
49 * | | | ` gp regs passed (0..8)
50 * | | ` fp regs passed (0..8)
51 * | ` indirect result register x8 used (0..1)
52 * ` env pointer passed in x9 (0..1)
56 isfloatv(Typ
*t
, char *cls
)
61 for (n
=0; n
<t
->nunion
; n
++)
62 for (f
=t
->fields
[n
]; f
->type
!= FEnd
; f
++)
75 if (isfloatv(&typ
[f
->len
], cls
))
85 typclass(Class
*c
, Typ
*t
, int *gp
, int *fp
)
90 sz
= (t
->size
+ 7) & -8;
97 err("alignments larger than 16 are not supported");
99 if (t
->isdark
|| sz
> 16 || sz
== 0) {
100 /* large structs are replaced by a
101 * pointer to some caller-allocated
113 c
->ishfa
= isfloatv(t
, &c
->hfa
.base
);
114 c
->hfa
.size
= t
->size
/(KWIDE(c
->hfa
.base
) ? 8 : 4);
117 for (n
=0; n
<c
->hfa
.size
; n
++, c
->nfp
++) {
119 c
->cls
[n
] = c
->hfa
.base
;
122 for (n
=0; n
<sz
/8; n
++, c
->ngp
++) {
131 sttmps(Ref tmp
[], int cls
[], uint nreg
, Ref mem
, Fn
*fn
)
134 [Kw
] = Ostorew
, [Kl
] = Ostorel
,
135 [Ks
] = Ostores
, [Kd
] = Ostored
143 for (n
=0; n
<nreg
; n
++) {
144 tmp
[n
] = newtmp("abi", cls
[n
], fn
);
145 r
= newtmp("abi", Kl
, fn
);
146 emit(st
[cls
[n
]], 0, R
, tmp
[n
], r
);
147 emit(Oadd
, Kl
, r
, mem
, getcon(off
, fn
));
148 off
+= KWIDE(cls
[n
]) ? 8 : 4;
152 /* todo, may read out of bounds */
154 ldregs(int reg
[], int cls
[], int n
, Ref mem
, Fn
*fn
)
161 for (i
=0; i
<n
; i
++) {
162 r
= newtmp("abi", Kl
, fn
);
163 emit(Oload
, cls
[i
], TMP(reg
[i
]), r
, R
);
164 emit(Oadd
, Kl
, r
, mem
, getcon(off
, fn
));
165 off
+= KWIDE(cls
[i
]) ? 8 : 4;
170 selret(Blk
*b
, Fn
*fn
)
178 if (!isret(j
) || j
== Jret0
)
185 typclass(&cr
, &typ
[fn
->retty
], gpreg
, fpreg
);
186 if (cr
.class & Cptr
) {
187 assert(rtype(fn
->retr
) == RTmp
);
188 blit0(fn
->retr
, r
, cr
.t
->size
, fn
);
191 ldregs(cr
.reg
, cr
.cls
, cr
.nreg
, r
, fn
);
192 cty
= (cr
.nfp
<< 2) | cr
.ngp
;
197 emit(Ocopy
, k
, TMP(R0
), r
, R
);
200 emit(Ocopy
, k
, TMP(V0
), r
, R
);
205 b
->jmp
.arg
= CALL(cty
);
209 argsclass(Ins
*i0
, Ins
*i1
, Class
*carg
)
211 int envc
, ngp
, nfp
, *gp
, *fp
;
220 for (i
=i0
, c
=carg
; i
<i1
; i
++, c
++)
226 if (KBASE(i
->cls
) == 0 && ngp
> 0) {
231 if (KBASE(i
->cls
) == 1 && nfp
> 0) {
240 typclass(c
, &typ
[i
->arg
[0].val
], gp
, fp
);
266 return envc
<< 14 | (gp
-gpreg
) << 5 | (fp
-fpreg
) << 9;
270 arm64_retregs(Ref r
, int p
[2])
275 assert(rtype(r
) == RCall
);
277 nfp
= (r
.val
>> 2) & 7;
291 arm64_argregs(Ref r
, int p
[2])
294 int ngp
, nfp
, x8
, x9
;
296 assert(rtype(r
) == RCall
);
297 ngp
= (r
.val
>> 5) & 15;
298 nfp
= (r
.val
>> 9) & 15;
299 x8
= (r
.val
>> 13) & 1;
300 x9
= (r
.val
>> 14) & 1;
302 p
[0] = ngp
+ x8
+ x9
;
310 return b
| ((bits
)x8
<< R8
) | ((bits
)x9
<< R9
);
314 stkblob(Ref r
, Class
*c
, Fn
*fn
, Insl
**ilp
)
320 il
= alloc(sizeof *il
);
321 al
= c
->t
->align
- 2; /* NAlign == 3 */
324 sz
= c
->class & Cptr
? c
->t
->size
: c
->size
;
325 il
->i
= (Ins
){Oalloc
+al
, Kl
, r
, {getcon(sz
, fn
)}};
331 selcall(Fn
*fn
, Ins
*i0
, Ins
*i1
, Insl
**ilp
)
340 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
341 cty
= argsclass(i0
, i1
, ca
);
344 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
345 if (c
->class & Cptr
) {
346 i
->arg
[0] = newtmp("abi", Kl
, fn
);
347 stkblob(i
->arg
[0], c
, fn
, ilp
);
354 rstk
= getcon(stk
, fn
);
356 emit(Oadd
, Kl
, TMP(SP
), TMP(SP
), rstk
);
358 if (!req(i1
->arg
[1], R
)) {
359 typclass(&cr
, &typ
[i1
->arg
[1].val
], gpreg
, fpreg
);
360 stkblob(i1
->to
, &cr
, fn
, ilp
);
361 cty
|= (cr
.nfp
<< 2) | cr
.ngp
;
362 if (cr
.class & Cptr
) {
363 /* spill & rega expect calls to be
364 * followed by copies from regs,
368 emit(Ocopy
, Kw
, R
, TMP(R0
), R
);
370 sttmps(tmp
, cr
.cls
, cr
.nreg
, i1
->to
, fn
);
371 for (n
=0; n
<cr
.nreg
; n
++) {
373 emit(Ocopy
, cr
.cls
[n
], tmp
[n
], r
, R
);
377 if (KBASE(i1
->cls
) == 0) {
378 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(R0
), R
);
381 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(V0
), R
);
386 emit(Ocall
, 0, R
, i1
->arg
[0], CALL(cty
));
389 /* struct return argument */
390 emit(Ocopy
, Kl
, TMP(R8
), i1
->to
, R
);
392 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
393 if ((c
->class & Cstk
) != 0)
395 if (i
->op
== Oarg
|| i
->op
== Oarge
)
396 emit(Ocopy
, *c
->cls
, TMP(*c
->reg
), i
->arg
[0], R
);
398 ldregs(c
->reg
, c
->cls
, c
->nreg
, i
->arg
[1], fn
);
401 /* populate the stack */
403 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
404 if ((c
->class & Cstk
) == 0)
407 r
= newtmp("abi", Kl
, fn
);
408 emit(Ostorel
, 0, R
, i
->arg
[0], r
);
409 emit(Oadd
, Kl
, r
, TMP(SP
), getcon(off
, fn
));
412 blit(TMP(SP
), off
, i
->arg
[1], 0, c
->size
, fn
);
416 emit(Osub
, Kl
, TMP(SP
), TMP(SP
), rstk
);
418 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
420 blit0(i
->arg
[0], i
->arg
[1], c
->t
->size
, fn
);
424 selpar(Fn
*fn
, Ins
*i0
, Ins
*i1
)
432 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
435 cty
= argsclass(i0
, i1
, ca
);
436 fn
->reg
= arm64_argregs(CALL(cty
), 0);
440 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
441 if (i
->op
!= Oparc
|| (c
->class & (Cptr
|Cstk
)))
443 sttmps(t
, c
->cls
, c
->nreg
, i
->to
, fn
);
444 stkblob(i
->to
, c
, fn
, &il
);
447 for (; il
; il
=il
->link
)
450 if (fn
->retty
>= 0) {
451 typclass(&cr
, &typ
[fn
->retty
], gpreg
, fpreg
);
452 if (cr
.class & Cptr
) {
453 fn
->retr
= newtmp("abi", Kl
, fn
);
454 emit(Ocopy
, Kl
, fn
->retr
, TMP(R8
), R
);
461 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
462 if (i
->op
== Oparc
&& !(c
->class & Cptr
)) {
463 if (c
->class & Cstk
) {
464 fn
->tmp
[i
->to
.val
].slot
= -s
;
467 for (n
=0; n
<c
->nreg
; n
++) {
469 emit(Ocopy
, c
->cls
[n
], *t
++, r
, R
);
471 } else if (c
->class & Cstk
) {
472 emit(Oload
, *c
->cls
, i
->to
, SLOT(-s
), R
);
475 emit(Ocopy
, *c
->cls
, i
->to
, TMP(*c
->reg
), R
);
480 .ngp
= (cty
>> 5) & 15,
481 .nfp
= (cty
>> 9) & 15
486 split(Fn
*fn
, Blk
*b
)
492 bn
->nins
= &insb
[NIns
] - curi
;
493 idup(&bn
->ins
, curi
, bn
->nins
);
495 bn
->visit
= ++b
->visit
;
496 (void)!snprintf(bn
->name
, NString
, "%s.%d", b
->name
, b
->visit
);
504 chpred(Blk
*b
, Blk
*bp
, Blk
*bp1
)
509 for (p
=b
->phi
; p
; p
=p
->link
) {
510 for (a
=0; p
->blk
[a
]!=bp
; a
++)
517 selvaarg(Fn
*fn
, Blk
*b
, Ins
*i
)
519 Ref loc
, lreg
, lstk
, nr
, r0
, r1
, c8
, c16
, c24
, c28
, ap
;
520 Blk
*b0
, *bstk
, *breg
;
524 c16
= getcon(16, fn
);
525 c24
= getcon(24, fn
);
526 c28
= getcon(28, fn
);
528 isgp
= KBASE(i
->cls
) == 0;
531 r0 =l add ap, (24 or 28)
536 r0 =l add ap, (8 or 16)
539 r0 =w add nr, (8 or 16)
540 r1 =l add ap, (24 or 28)
547 %loc =l phi @breg %lreg, @bstk %lstk
548 i->to =(i->cls) load %loc
551 loc
= newtmp("abi", Kl
, fn
);
552 emit(Oload
, i
->cls
, i
->to
, loc
, R
);
558 chpred(b
->s1
, b
, b0
);
559 if (b
->s2
&& b
->s2
!= b
->s1
)
560 chpred(b
->s2
, b
, b0
);
562 lreg
= newtmp("abi", Kl
, fn
);
563 nr
= newtmp("abi", Kl
, fn
);
564 r0
= newtmp("abi", Kw
, fn
);
565 r1
= newtmp("abi", Kl
, fn
);
566 emit(Ostorew
, Kw
, R
, r0
, r1
);
567 emit(Oadd
, Kl
, r1
, ap
, isgp
? c24
: c28
);
568 emit(Oadd
, Kw
, r0
, nr
, isgp
? c8
: c16
);
569 r0
= newtmp("abi", Kl
, fn
);
570 r1
= newtmp("abi", Kl
, fn
);
571 emit(Oadd
, Kl
, lreg
, r1
, nr
);
572 emit(Oload
, Kl
, r1
, r0
, R
);
573 emit(Oadd
, Kl
, r0
, ap
, isgp
? c8
: c16
);
575 breg
->jmp
.type
= Jjmp
;
578 lstk
= newtmp("abi", Kl
, fn
);
579 r0
= newtmp("abi", Kl
, fn
);
580 emit(Ostorel
, Kw
, R
, r0
, ap
);
581 emit(Oadd
, Kl
, r0
, lstk
, c8
);
582 emit(Oload
, Kl
, lstk
, ap
, R
);
584 bstk
->jmp
.type
= Jjmp
;
587 b0
->phi
= alloc(sizeof *b0
->phi
);
589 .cls
= Kl
, .to
= loc
,
591 .blk
= vnew(2, sizeof b0
->phi
->blk
[0], Pfn
),
592 .arg
= vnew(2, sizeof b0
->phi
->arg
[0], Pfn
),
594 b0
->phi
->blk
[0] = bstk
;
595 b0
->phi
->blk
[1] = breg
;
596 b0
->phi
->arg
[0] = lstk
;
597 b0
->phi
->arg
[1] = lreg
;
598 r0
= newtmp("abi", Kl
, fn
);
599 r1
= newtmp("abi", Kw
, fn
);
604 emit(Ocmpw
+Cislt
, Kw
, r1
, nr
, CON_Z
);
605 emit(Oloadsw
, Kl
, nr
, r0
, R
);
606 emit(Oadd
, Kl
, r0
, ap
, isgp
? c24
: c28
);
610 selvastart(Fn
*fn
, Params p
, Ref ap
)
614 rsave
= newtmp("abi", Kl
, fn
);
616 r0
= newtmp("abi", Kl
, fn
);
617 emit(Ostorel
, Kw
, R
, r0
, ap
);
618 emit(Oadd
, Kl
, r0
, rsave
, getcon(p
.nstk
*8 + 192, fn
));
620 r0
= newtmp("abi", Kl
, fn
);
621 r1
= newtmp("abi", Kl
, fn
);
622 emit(Ostorel
, Kw
, R
, r1
, r0
);
623 emit(Oadd
, Kl
, r1
, rsave
, getcon(64, fn
));
624 emit(Oadd
, Kl
, r0
, ap
, getcon(8, fn
));
626 r0
= newtmp("abi", Kl
, fn
);
627 r1
= newtmp("abi", Kl
, fn
);
628 emit(Ostorel
, Kw
, R
, r1
, r0
);
629 emit(Oadd
, Kl
, r1
, rsave
, getcon(192, fn
));
630 emit(Oaddr
, Kl
, rsave
, SLOT(-1), R
);
631 emit(Oadd
, Kl
, r0
, ap
, getcon(16, fn
));
633 r0
= newtmp("abi", Kl
, fn
);
634 emit(Ostorew
, Kw
, R
, getcon((p
.ngp
-8)*8, fn
), r0
);
635 emit(Oadd
, Kl
, r0
, ap
, getcon(24, fn
));
637 r0
= newtmp("abi", Kl
, fn
);
638 emit(Ostorew
, Kw
, R
, getcon((p
.nfp
-8)*16, fn
), r0
);
639 emit(Oadd
, Kl
, r0
, ap
, getcon(28, fn
));
651 for (b
=fn
->start
; b
; b
=b
->link
)
654 /* lower parameters */
655 for (b
=fn
->start
, i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
658 p
= selpar(fn
, b
->ins
, i
);
659 n
= b
->nins
- (i
- b
->ins
) + (&insb
[NIns
] - curi
);
660 i0
= alloc(n
* sizeof(Ins
));
661 ip
= icpy(ip
= i0
, curi
, &insb
[NIns
] - curi
);
662 ip
= icpy(ip
, i
, &b
->ins
[b
->nins
] - i
);
666 /* lower calls, returns, and vararg instructions */
671 b
= fn
->start
; /* do it last */
676 for (i
=&b
->ins
[b
->nins
]; i
!=b
->ins
;)
682 for (i0
=i
; i0
>b
->ins
; i0
--)
683 if (!isarg((i0
-1)->op
))
685 selcall(fn
, i0
, i
, &il
);
689 selvastart(fn
, p
, i
->arg
[0]);
699 for (; il
; il
=il
->link
)
701 b
->nins
= &insb
[NIns
] - curi
;
702 idup(&b
->ins
, curi
, b
->nins
);
703 } while (b
!= fn
->start
);
706 fprintf(stderr
, "\n> After ABI lowering:\n");