3 typedef struct Abi Abi
;
4 typedef struct Class Class
;
5 typedef struct Insl Insl
;
6 typedef struct Params Params
;
9 Cstk
= 1, /* pass on the stack */
10 Cptr
= 2, /* replaced by a pointer */
41 static int gpreg
[12] = {R0
, R1
, R2
, R3
, R4
, R5
, R6
, R7
};
42 static int fpreg
[12] = {V0
, V1
, V2
, V3
, V4
, V5
, V6
, V7
};
43 static int store
[] = {
44 [Kw
] = Ostorew
, [Kl
] = Ostorel
,
45 [Ks
] = Ostores
, [Kd
] = Ostored
48 /* layout of call's second argument (RCall)
52 * |0.00|x|x|xxxx|xxxx|xxx|xx| range
53 * | | | | | ` gp regs returned (0..2)
54 * | | | | ` fp regs returned (0..4)
55 * | | | ` gp regs passed (0..8)
56 * | | ` fp regs passed (0..8)
57 * | ` indirect result register x8 used (0..1)
58 * ` env pointer passed in x9 (0..1)
62 isfloatv(Typ
*t
, char *cls
)
67 for (n
=0; n
<t
->nunion
; n
++)
68 for (f
=t
->fields
[n
]; f
->type
!= FEnd
; f
++)
81 if (isfloatv(&typ
[f
->len
], cls
))
91 typclass(Class
*c
, Typ
*t
, int *gp
, int *fp
)
96 sz
= (t
->size
+ 7) & -8;
104 err("alignments larger than 8 are not supported");
106 if (t
->isdark
|| sz
> 16 || sz
== 0) {
107 /* large structs are replaced by a
108 * pointer to some caller-allocated
120 c
->ishfa
= isfloatv(t
, &c
->hfa
.base
);
121 c
->hfa
.size
= t
->size
/(KWIDE(c
->hfa
.base
) ? 8 : 4);
124 for (n
=0; n
<c
->hfa
.size
; n
++, c
->nfp
++) {
126 c
->cls
[n
] = c
->hfa
.base
;
129 for (n
=0; n
<sz
/8; n
++, c
->ngp
++) {
138 sttmps(Ref tmp
[], int cls
[], uint nreg
, Ref mem
, Fn
*fn
)
146 for (n
=0; n
<nreg
; n
++) {
147 tmp
[n
] = newtmp("abi", cls
[n
], fn
);
148 r
= newtmp("abi", Kl
, fn
);
149 emit(store
[cls
[n
]], 0, R
, tmp
[n
], r
);
150 emit(Oadd
, Kl
, r
, mem
, getcon(off
, fn
));
151 off
+= KWIDE(cls
[n
]) ? 8 : 4;
155 /* todo, may read out of bounds */
157 ldregs(int reg
[], int cls
[], int n
, Ref mem
, Fn
*fn
)
164 for (i
=0; i
<n
; i
++) {
165 r
= newtmp("abi", Kl
, fn
);
166 emit(Oload
, cls
[i
], TMP(reg
[i
]), r
, R
);
167 emit(Oadd
, Kl
, r
, mem
, getcon(off
, fn
));
168 off
+= KWIDE(cls
[i
]) ? 8 : 4;
173 selret(Blk
*b
, Fn
*fn
)
181 if (!isret(j
) || j
== Jret0
)
188 typclass(&cr
, &typ
[fn
->retty
], gpreg
, fpreg
);
189 if (cr
.class & Cptr
) {
190 assert(rtype(fn
->retr
) == RTmp
);
191 emit(Oblit1
, 0, R
, INT(cr
.t
->size
), R
);
192 emit(Oblit0
, 0, R
, r
, fn
->retr
);
195 ldregs(cr
.reg
, cr
.cls
, cr
.nreg
, r
, fn
);
196 cty
= (cr
.nfp
<< 2) | cr
.ngp
;
201 emit(Ocopy
, k
, TMP(R0
), r
, R
);
204 emit(Ocopy
, k
, TMP(V0
), r
, R
);
209 b
->jmp
.arg
= CALL(cty
);
213 argsclass(Ins
*i0
, Ins
*i1
, Class
*carg
)
215 int va
, envc
, ngp
, nfp
, *gp
, *fp
;
225 for (i
=i0
, c
=carg
; i
<i1
; i
++, c
++)
242 if (T
.apple
&& !KWIDE(i
->cls
))
253 if (KBASE(i
->cls
) == 0 && ngp
> 0) {
258 if (KBASE(i
->cls
) == 1 && nfp
> 0) {
267 typclass(c
, &typ
[i
->arg
[0].val
], gp
, fp
);
294 return envc
<< 14 | (gp
-gpreg
) << 5 | (fp
-fpreg
) << 9;
298 arm64_retregs(Ref r
, int p
[2])
303 assert(rtype(r
) == RCall
);
305 nfp
= (r
.val
>> 2) & 7;
319 arm64_argregs(Ref r
, int p
[2])
322 int ngp
, nfp
, x8
, x9
;
324 assert(rtype(r
) == RCall
);
325 ngp
= (r
.val
>> 5) & 15;
326 nfp
= (r
.val
>> 9) & 15;
327 x8
= (r
.val
>> 13) & 1;
328 x9
= (r
.val
>> 14) & 1;
330 p
[0] = ngp
+ x8
+ x9
;
338 return b
| ((bits
)x8
<< R8
) | ((bits
)x9
<< R9
);
342 stkblob(Ref r
, Class
*c
, Fn
*fn
, Insl
**ilp
)
348 il
= alloc(sizeof *il
);
349 al
= c
->t
->align
- 2; /* NAlign == 3 */
352 sz
= c
->class & Cptr
? c
->t
->size
: c
->size
;
353 il
->i
= (Ins
){Oalloc
+al
, Kl
, r
, {getcon(sz
, fn
)}};
359 align(uint x
, uint al
)
361 return (x
+ al
-1) & -al
;
365 selcall(Fn
*fn
, Ins
*i0
, Ins
*i1
, Insl
**ilp
)
373 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
374 cty
= argsclass(i0
, i1
, ca
);
377 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
378 if (c
->class & Cptr
) {
379 i
->arg
[0] = newtmp("abi", Kl
, fn
);
380 stkblob(i
->arg
[0], c
, fn
, ilp
);
383 if (c
->class & Cstk
) {
384 stk
= align(stk
, c
->align
);
388 stk
= align(stk
, 16);
389 rstk
= getcon(stk
, fn
);
391 emit(Oadd
, Kl
, TMP(SP
), TMP(SP
), rstk
);
393 if (!req(i1
->arg
[1], R
)) {
394 typclass(&cr
, &typ
[i1
->arg
[1].val
], gpreg
, fpreg
);
395 stkblob(i1
->to
, &cr
, fn
, ilp
);
396 cty
|= (cr
.nfp
<< 2) | cr
.ngp
;
397 if (cr
.class & Cptr
) {
398 /* spill & rega expect calls to be
399 * followed by copies from regs,
403 emit(Ocopy
, Kw
, R
, TMP(R0
), R
);
405 sttmps(tmp
, cr
.cls
, cr
.nreg
, i1
->to
, fn
);
406 for (n
=0; n
<cr
.nreg
; n
++) {
408 emit(Ocopy
, cr
.cls
[n
], tmp
[n
], r
, R
);
412 if (KBASE(i1
->cls
) == 0) {
413 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(R0
), R
);
416 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(V0
), R
);
421 emit(Ocall
, 0, R
, i1
->arg
[0], CALL(cty
));
424 /* struct return argument */
425 emit(Ocopy
, Kl
, TMP(R8
), i1
->to
, R
);
427 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
428 if ((c
->class & Cstk
) != 0)
430 if (i
->op
== Oarg
|| i
->op
== Oarge
)
431 emit(Ocopy
, *c
->cls
, TMP(*c
->reg
), i
->arg
[0], R
);
433 ldregs(c
->reg
, c
->cls
, c
->nreg
, i
->arg
[1], fn
);
436 /* populate the stack */
438 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
439 if ((c
->class & Cstk
) == 0)
441 off
= align(off
, c
->align
);
442 r
= newtmp("abi", Kl
, fn
);
443 if (i
->op
== Oarg
|| isargbh(i
->op
)) {
445 case 1: op
= Ostoreb
; break;
446 case 2: op
= Ostoreh
; break;
448 case 8: op
= store
[*c
->cls
]; break;
449 default: die("unreachable");
451 emit(op
, 0, R
, i
->arg
[0], r
);
453 assert(i
->op
== Oargc
);
454 emit(Oblit1
, 0, R
, INT(c
->size
), R
);
455 emit(Oblit0
, 0, R
, i
->arg
[1], r
);
457 emit(Oadd
, Kl
, r
, TMP(SP
), getcon(off
, fn
));
461 emit(Osub
, Kl
, TMP(SP
), TMP(SP
), rstk
);
463 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
464 if (c
->class & Cptr
) {
465 emit(Oblit1
, 0, R
, INT(c
->t
->size
), R
);
466 emit(Oblit0
, 0, R
, i
->arg
[1], i
->arg
[0]);
471 selpar(Fn
*fn
, Ins
*i0
, Ins
*i1
)
480 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
483 cty
= argsclass(i0
, i1
, ca
);
484 fn
->reg
= arm64_argregs(CALL(cty
), 0);
488 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
489 if (i
->op
!= Oparc
|| (c
->class & (Cptr
|Cstk
)))
491 sttmps(t
, c
->cls
, c
->nreg
, i
->to
, fn
);
492 stkblob(i
->to
, c
, fn
, &il
);
495 for (; il
; il
=il
->link
)
498 if (fn
->retty
>= 0) {
499 typclass(&cr
, &typ
[fn
->retty
], gpreg
, fpreg
);
500 if (cr
.class & Cptr
) {
501 fn
->retr
= newtmp("abi", Kl
, fn
);
502 emit(Ocopy
, Kl
, fn
->retr
, TMP(R8
), R
);
509 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
510 if (i
->op
== Oparc
&& !(c
->class & Cptr
)) {
511 if (c
->class & Cstk
) {
512 off
= align(off
, c
->align
);
513 fn
->tmp
[i
->to
.val
].slot
= -(off
+2);
516 for (n
=0; n
<c
->nreg
; n
++) {
518 emit(Ocopy
, c
->cls
[n
], *t
++, r
, R
);
520 } else if (c
->class & Cstk
) {
521 off
= align(off
, c
->align
);
523 op
= Oloadsb
+ (i
->op
- Oparsb
);
526 emit(op
, *c
->cls
, i
->to
, SLOT(-(off
+2)), R
);
529 emit(Ocopy
, *c
->cls
, i
->to
, TMP(*c
->reg
), R
);
533 .stk
= align(off
, 8),
534 .ngp
= (cty
>> 5) & 15,
535 .nfp
= (cty
>> 9) & 15
540 split(Fn
*fn
, Blk
*b
)
546 bn
->nins
= &insb
[NIns
] - curi
;
547 idup(&bn
->ins
, curi
, bn
->nins
);
549 bn
->visit
= ++b
->visit
;
550 strf(bn
->name
, "%s.%d", b
->name
, b
->visit
);
558 chpred(Blk
*b
, Blk
*bp
, Blk
*bp1
)
563 for (p
=b
->phi
; p
; p
=p
->link
) {
564 for (a
=0; p
->blk
[a
]!=bp
; a
++)
571 apple_selvaarg(Fn
*fn
, Blk
*b
, Ins
*i
)
573 Ref ap
, stk
, stk8
, c8
;
578 stk8
= newtmp("abi", Kl
, fn
);
579 stk
= newtmp("abi", Kl
, fn
);
581 emit(Ostorel
, 0, R
, stk8
, ap
);
582 emit(Oadd
, Kl
, stk8
, stk
, c8
);
583 emit(Oload
, i
->cls
, i
->to
, stk
, R
);
584 emit(Oload
, Kl
, stk
, ap
, R
);
588 arm64_selvaarg(Fn
*fn
, Blk
*b
, Ins
*i
)
590 Ref loc
, lreg
, lstk
, nr
, r0
, r1
, c8
, c16
, c24
, c28
, ap
;
591 Blk
*b0
, *bstk
, *breg
;
595 c16
= getcon(16, fn
);
596 c24
= getcon(24, fn
);
597 c28
= getcon(28, fn
);
599 isgp
= KBASE(i
->cls
) == 0;
602 r0 =l add ap, (24 or 28)
607 r0 =l add ap, (8 or 16)
610 r0 =w add nr, (8 or 16)
611 r1 =l add ap, (24 or 28)
618 %loc =l phi @breg %lreg, @bstk %lstk
619 i->to =(i->cls) load %loc
622 loc
= newtmp("abi", Kl
, fn
);
623 emit(Oload
, i
->cls
, i
->to
, loc
, R
);
629 chpred(b
->s1
, b
, b0
);
630 if (b
->s2
&& b
->s2
!= b
->s1
)
631 chpred(b
->s2
, b
, b0
);
633 lreg
= newtmp("abi", Kl
, fn
);
634 nr
= newtmp("abi", Kl
, fn
);
635 r0
= newtmp("abi", Kw
, fn
);
636 r1
= newtmp("abi", Kl
, fn
);
637 emit(Ostorew
, Kw
, R
, r0
, r1
);
638 emit(Oadd
, Kl
, r1
, ap
, isgp
? c24
: c28
);
639 emit(Oadd
, Kw
, r0
, nr
, isgp
? c8
: c16
);
640 r0
= newtmp("abi", Kl
, fn
);
641 r1
= newtmp("abi", Kl
, fn
);
642 emit(Oadd
, Kl
, lreg
, r1
, nr
);
643 emit(Oload
, Kl
, r1
, r0
, R
);
644 emit(Oadd
, Kl
, r0
, ap
, isgp
? c8
: c16
);
646 breg
->jmp
.type
= Jjmp
;
649 lstk
= newtmp("abi", Kl
, fn
);
650 r0
= newtmp("abi", Kl
, fn
);
651 emit(Ostorel
, Kw
, R
, r0
, ap
);
652 emit(Oadd
, Kl
, r0
, lstk
, c8
);
653 emit(Oload
, Kl
, lstk
, ap
, R
);
655 bstk
->jmp
.type
= Jjmp
;
658 b0
->phi
= alloc(sizeof *b0
->phi
);
660 .cls
= Kl
, .to
= loc
,
662 .blk
= vnew(2, sizeof b0
->phi
->blk
[0], PFn
),
663 .arg
= vnew(2, sizeof b0
->phi
->arg
[0], PFn
),
665 b0
->phi
->blk
[0] = bstk
;
666 b0
->phi
->blk
[1] = breg
;
667 b0
->phi
->arg
[0] = lstk
;
668 b0
->phi
->arg
[1] = lreg
;
669 r0
= newtmp("abi", Kl
, fn
);
670 r1
= newtmp("abi", Kw
, fn
);
675 emit(Ocmpw
+Cislt
, Kw
, r1
, nr
, CON_Z
);
676 emit(Oloadsw
, Kl
, nr
, r0
, R
);
677 emit(Oadd
, Kl
, r0
, ap
, isgp
? c24
: c28
);
681 apple_selvastart(Fn
*fn
, Params p
, Ref ap
)
685 off
= getcon(p
.stk
, fn
);
686 stk
= newtmp("abi", Kl
, fn
);
687 arg
= newtmp("abi", Kl
, fn
);
689 emit(Ostorel
, 0, R
, arg
, ap
);
690 emit(Oadd
, Kl
, arg
, stk
, off
);
691 emit(Oaddr
, Kl
, stk
, SLOT(-1), R
);
695 arm64_selvastart(Fn
*fn
, Params p
, Ref ap
)
699 rsave
= newtmp("abi", Kl
, fn
);
701 r0
= newtmp("abi", Kl
, fn
);
702 emit(Ostorel
, Kw
, R
, r0
, ap
);
703 emit(Oadd
, Kl
, r0
, rsave
, getcon(p
.stk
+ 192, fn
));
705 r0
= newtmp("abi", Kl
, fn
);
706 r1
= newtmp("abi", Kl
, fn
);
707 emit(Ostorel
, Kw
, R
, r1
, r0
);
708 emit(Oadd
, Kl
, r1
, rsave
, getcon(64, fn
));
709 emit(Oadd
, Kl
, r0
, ap
, getcon(8, fn
));
711 r0
= newtmp("abi", Kl
, fn
);
712 r1
= newtmp("abi", Kl
, fn
);
713 emit(Ostorel
, Kw
, R
, r1
, r0
);
714 emit(Oadd
, Kl
, r1
, rsave
, getcon(192, fn
));
715 emit(Oaddr
, Kl
, rsave
, SLOT(-1), R
);
716 emit(Oadd
, Kl
, r0
, ap
, getcon(16, fn
));
718 r0
= newtmp("abi", Kl
, fn
);
719 emit(Ostorew
, Kw
, R
, getcon((p
.ngp
-8)*8, fn
), r0
);
720 emit(Oadd
, Kl
, r0
, ap
, getcon(24, fn
));
722 r0
= newtmp("abi", Kl
, fn
);
723 emit(Ostorew
, Kw
, R
, getcon((p
.nfp
-8)*16, fn
), r0
);
724 emit(Oadd
, Kl
, r0
, ap
, getcon(28, fn
));
736 for (b
=fn
->start
; b
; b
=b
->link
)
739 /* lower parameters */
740 for (b
=fn
->start
, i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
743 p
= selpar(fn
, b
->ins
, i
);
744 n
= b
->nins
- (i
- b
->ins
) + (&insb
[NIns
] - curi
);
745 i0
= alloc(n
* sizeof(Ins
));
746 ip
= icpy(ip
= i0
, curi
, &insb
[NIns
] - curi
);
747 ip
= icpy(ip
, i
, &b
->ins
[b
->nins
] - i
);
751 /* lower calls, returns, and vararg instructions */
756 b
= fn
->start
; /* do it last */
761 for (i
=&b
->ins
[b
->nins
]; i
!=b
->ins
;)
767 for (i0
=i
; i0
>b
->ins
; i0
--)
768 if (!isarg((i0
-1)->op
))
770 selcall(fn
, i0
, i
, &il
);
775 apple_selvastart(fn
, p
, i
->arg
[0]);
777 arm64_selvastart(fn
, p
, i
->arg
[0]);
781 apple_selvaarg(fn
, b
, i
);
783 arm64_selvaarg(fn
, b
, i
);
790 for (; il
; il
=il
->link
)
792 b
->nins
= &insb
[NIns
] - curi
;
793 idup(&b
->ins
, curi
, b
->nins
);
794 } while (b
!= fn
->start
);
797 fprintf(stderr
, "\n> After ABI lowering:\n");
802 /* abi0 for apple target; introduces
803 * necessary sign extensions in calls
814 for (b
=fn
->start
; b
; b
=b
->link
) {
818 r
= newtmp("abi", Kw
, fn
);
819 op
= Oextsb
+ (j
- Jretsb
);
820 emit(op
, Kw
, r
, b
->jmp
.arg
, R
);
824 for (i
=&b
->ins
[b
->nins
]; i
>b
->ins
;) {
828 for (i0
=i1
=i
; i0
>b
->ins
; i0
--)
829 if (!isarg((i0
-1)->op
))
833 if (isargbh(i
->op
)) {
834 i
->to
= newtmp("abi", Kl
, fn
);
835 curi
->arg
[0] = i
->to
;
839 if (isargbh((--i
)->op
)) {
840 op
= Oextsb
+ (i
->op
- Oargsb
);
841 emit(op
, Kw
, i
->to
, i
->arg
[0], R
);
844 b
->nins
= &insb
[NIns
] - curi
;
845 idup(&b
->ins
, curi
, b
->nins
);
849 fprintf(stderr
, "\n> After Apple pre-ABI:\n");