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 blit0(fn
->retr
, r
, cr
.t
->size
, fn
);
194 ldregs(cr
.reg
, cr
.cls
, cr
.nreg
, r
, fn
);
195 cty
= (cr
.nfp
<< 2) | cr
.ngp
;
200 emit(Ocopy
, k
, TMP(R0
), r
, R
);
203 emit(Ocopy
, k
, TMP(V0
), r
, R
);
208 b
->jmp
.arg
= CALL(cty
);
212 argsclass(Ins
*i0
, Ins
*i1
, Class
*carg
)
214 int va
, envc
, ngp
, nfp
, *gp
, *fp
;
224 for (i
=i0
, c
=carg
; i
<i1
; i
++, c
++)
241 if (T
.apple
&& !KWIDE(i
->cls
))
252 if (KBASE(i
->cls
) == 0 && ngp
> 0) {
257 if (KBASE(i
->cls
) == 1 && nfp
> 0) {
266 typclass(c
, &typ
[i
->arg
[0].val
], gp
, fp
);
293 return envc
<< 14 | (gp
-gpreg
) << 5 | (fp
-fpreg
) << 9;
297 arm64_retregs(Ref r
, int p
[2])
302 assert(rtype(r
) == RCall
);
304 nfp
= (r
.val
>> 2) & 7;
318 arm64_argregs(Ref r
, int p
[2])
321 int ngp
, nfp
, x8
, x9
;
323 assert(rtype(r
) == RCall
);
324 ngp
= (r
.val
>> 5) & 15;
325 nfp
= (r
.val
>> 9) & 15;
326 x8
= (r
.val
>> 13) & 1;
327 x9
= (r
.val
>> 14) & 1;
329 p
[0] = ngp
+ x8
+ x9
;
337 return b
| ((bits
)x8
<< R8
) | ((bits
)x9
<< R9
);
341 stkblob(Ref r
, Class
*c
, Fn
*fn
, Insl
**ilp
)
347 il
= alloc(sizeof *il
);
348 al
= c
->t
->align
- 2; /* NAlign == 3 */
351 sz
= c
->class & Cptr
? c
->t
->size
: c
->size
;
352 il
->i
= (Ins
){Oalloc
+al
, Kl
, r
, {getcon(sz
, fn
)}};
358 align(uint x
, uint al
)
360 return (x
+ al
-1) & -al
;
364 selcall(Fn
*fn
, Ins
*i0
, Ins
*i1
, Insl
**ilp
)
372 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
373 cty
= argsclass(i0
, i1
, ca
);
376 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
377 if (c
->class & Cptr
) {
378 i
->arg
[0] = newtmp("abi", Kl
, fn
);
379 stkblob(i
->arg
[0], c
, fn
, ilp
);
382 if (c
->class & Cstk
) {
383 stk
= align(stk
, c
->align
);
387 stk
= align(stk
, 16);
388 rstk
= getcon(stk
, fn
);
390 emit(Oadd
, Kl
, TMP(SP
), TMP(SP
), rstk
);
392 if (!req(i1
->arg
[1], R
)) {
393 typclass(&cr
, &typ
[i1
->arg
[1].val
], gpreg
, fpreg
);
394 stkblob(i1
->to
, &cr
, fn
, ilp
);
395 cty
|= (cr
.nfp
<< 2) | cr
.ngp
;
396 if (cr
.class & Cptr
) {
397 /* spill & rega expect calls to be
398 * followed by copies from regs,
402 emit(Ocopy
, Kw
, R
, TMP(R0
), R
);
404 sttmps(tmp
, cr
.cls
, cr
.nreg
, i1
->to
, fn
);
405 for (n
=0; n
<cr
.nreg
; n
++) {
407 emit(Ocopy
, cr
.cls
[n
], tmp
[n
], r
, R
);
411 if (KBASE(i1
->cls
) == 0) {
412 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(R0
), R
);
415 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(V0
), R
);
420 emit(Ocall
, 0, R
, i1
->arg
[0], CALL(cty
));
423 /* struct return argument */
424 emit(Ocopy
, Kl
, TMP(R8
), i1
->to
, R
);
426 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
427 if ((c
->class & Cstk
) != 0)
429 if (i
->op
== Oarg
|| i
->op
== Oarge
)
430 emit(Ocopy
, *c
->cls
, TMP(*c
->reg
), i
->arg
[0], R
);
432 ldregs(c
->reg
, c
->cls
, c
->nreg
, i
->arg
[1], fn
);
435 /* populate the stack */
437 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
438 if ((c
->class & Cstk
) == 0)
440 off
= align(off
, c
->align
);
441 if (i
->op
== Oarg
|| isargbh(i
->op
)) {
442 r
= newtmp("abi", Kl
, fn
);
444 case 1: op
= Ostoreb
; break;
445 case 2: op
= Ostoreh
; break;
447 case 8: op
= store
[*c
->cls
]; break;
449 emit(op
, 0, R
, i
->arg
[0], r
);
450 emit(Oadd
, Kl
, r
, TMP(SP
), getcon(off
, fn
));
453 blit(TMP(SP
), off
, i
->arg
[1], 0, c
->size
, fn
);
457 emit(Osub
, Kl
, TMP(SP
), TMP(SP
), rstk
);
459 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
461 blit0(i
->arg
[0], i
->arg
[1], c
->t
->size
, fn
);
465 selpar(Fn
*fn
, Ins
*i0
, Ins
*i1
)
474 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
477 cty
= argsclass(i0
, i1
, ca
);
478 fn
->reg
= arm64_argregs(CALL(cty
), 0);
482 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
483 if (i
->op
!= Oparc
|| (c
->class & (Cptr
|Cstk
)))
485 sttmps(t
, c
->cls
, c
->nreg
, i
->to
, fn
);
486 stkblob(i
->to
, c
, fn
, &il
);
489 for (; il
; il
=il
->link
)
492 if (fn
->retty
>= 0) {
493 typclass(&cr
, &typ
[fn
->retty
], gpreg
, fpreg
);
494 if (cr
.class & Cptr
) {
495 fn
->retr
= newtmp("abi", Kl
, fn
);
496 emit(Ocopy
, Kl
, fn
->retr
, TMP(R8
), R
);
503 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
504 if (i
->op
== Oparc
&& !(c
->class & Cptr
)) {
505 if (c
->class & Cstk
) {
506 off
= align(off
, c
->align
);
507 fn
->tmp
[i
->to
.val
].slot
= -(off
+2);
510 for (n
=0; n
<c
->nreg
; n
++) {
512 emit(Ocopy
, c
->cls
[n
], *t
++, r
, R
);
514 } else if (c
->class & Cstk
) {
515 off
= align(off
, c
->align
);
517 op
= Oloadsb
+ (i
->op
- Oparsb
);
520 emit(op
, *c
->cls
, i
->to
, SLOT(-(off
+2)), R
);
523 emit(Ocopy
, *c
->cls
, i
->to
, TMP(*c
->reg
), R
);
527 .stk
= align(off
, 8),
528 .ngp
= (cty
>> 5) & 15,
529 .nfp
= (cty
>> 9) & 15
534 split(Fn
*fn
, Blk
*b
)
540 bn
->nins
= &insb
[NIns
] - curi
;
541 idup(&bn
->ins
, curi
, bn
->nins
);
543 bn
->visit
= ++b
->visit
;
544 (void)!snprintf(bn
->name
, NString
, "%s.%d", b
->name
, b
->visit
);
552 chpred(Blk
*b
, Blk
*bp
, Blk
*bp1
)
557 for (p
=b
->phi
; p
; p
=p
->link
) {
558 for (a
=0; p
->blk
[a
]!=bp
; a
++)
565 apple_selvaarg(Fn
*fn
, Blk
*b
, Ins
*i
)
567 Ref ap
, stk
, stk8
, c8
;
572 stk8
= newtmp("abi", Kl
, fn
);
573 stk
= newtmp("abi", Kl
, fn
);
575 emit(Ostorel
, 0, R
, stk8
, ap
);
576 emit(Oadd
, Kl
, stk8
, stk
, c8
);
577 emit(Oload
, i
->cls
, i
->to
, stk
, R
);
578 emit(Oload
, Kl
, stk
, ap
, R
);
582 arm64_selvaarg(Fn
*fn
, Blk
*b
, Ins
*i
)
584 Ref loc
, lreg
, lstk
, nr
, r0
, r1
, c8
, c16
, c24
, c28
, ap
;
585 Blk
*b0
, *bstk
, *breg
;
589 c16
= getcon(16, fn
);
590 c24
= getcon(24, fn
);
591 c28
= getcon(28, fn
);
593 isgp
= KBASE(i
->cls
) == 0;
596 r0 =l add ap, (24 or 28)
601 r0 =l add ap, (8 or 16)
604 r0 =w add nr, (8 or 16)
605 r1 =l add ap, (24 or 28)
612 %loc =l phi @breg %lreg, @bstk %lstk
613 i->to =(i->cls) load %loc
616 loc
= newtmp("abi", Kl
, fn
);
617 emit(Oload
, i
->cls
, i
->to
, loc
, R
);
623 chpred(b
->s1
, b
, b0
);
624 if (b
->s2
&& b
->s2
!= b
->s1
)
625 chpred(b
->s2
, b
, b0
);
627 lreg
= newtmp("abi", Kl
, fn
);
628 nr
= newtmp("abi", Kl
, fn
);
629 r0
= newtmp("abi", Kw
, fn
);
630 r1
= newtmp("abi", Kl
, fn
);
631 emit(Ostorew
, Kw
, R
, r0
, r1
);
632 emit(Oadd
, Kl
, r1
, ap
, isgp
? c24
: c28
);
633 emit(Oadd
, Kw
, r0
, nr
, isgp
? c8
: c16
);
634 r0
= newtmp("abi", Kl
, fn
);
635 r1
= newtmp("abi", Kl
, fn
);
636 emit(Oadd
, Kl
, lreg
, r1
, nr
);
637 emit(Oload
, Kl
, r1
, r0
, R
);
638 emit(Oadd
, Kl
, r0
, ap
, isgp
? c8
: c16
);
640 breg
->jmp
.type
= Jjmp
;
643 lstk
= newtmp("abi", Kl
, fn
);
644 r0
= newtmp("abi", Kl
, fn
);
645 emit(Ostorel
, Kw
, R
, r0
, ap
);
646 emit(Oadd
, Kl
, r0
, lstk
, c8
);
647 emit(Oload
, Kl
, lstk
, ap
, R
);
649 bstk
->jmp
.type
= Jjmp
;
652 b0
->phi
= alloc(sizeof *b0
->phi
);
654 .cls
= Kl
, .to
= loc
,
656 .blk
= vnew(2, sizeof b0
->phi
->blk
[0], PFn
),
657 .arg
= vnew(2, sizeof b0
->phi
->arg
[0], PFn
),
659 b0
->phi
->blk
[0] = bstk
;
660 b0
->phi
->blk
[1] = breg
;
661 b0
->phi
->arg
[0] = lstk
;
662 b0
->phi
->arg
[1] = lreg
;
663 r0
= newtmp("abi", Kl
, fn
);
664 r1
= newtmp("abi", Kw
, fn
);
669 emit(Ocmpw
+Cislt
, Kw
, r1
, nr
, CON_Z
);
670 emit(Oloadsw
, Kl
, nr
, r0
, R
);
671 emit(Oadd
, Kl
, r0
, ap
, isgp
? c24
: c28
);
675 apple_selvastart(Fn
*fn
, Params p
, Ref ap
)
679 off
= getcon(p
.stk
, fn
);
680 stk
= newtmp("abi", Kl
, fn
);
681 arg
= newtmp("abi", Kl
, fn
);
683 emit(Ostorel
, 0, R
, arg
, ap
);
684 emit(Oadd
, Kl
, arg
, stk
, off
);
685 emit(Oaddr
, Kl
, stk
, SLOT(-1), R
);
689 arm64_selvastart(Fn
*fn
, Params p
, Ref ap
)
693 rsave
= newtmp("abi", Kl
, fn
);
695 r0
= newtmp("abi", Kl
, fn
);
696 emit(Ostorel
, Kw
, R
, r0
, ap
);
697 emit(Oadd
, Kl
, r0
, rsave
, getcon(p
.stk
+ 192, fn
));
699 r0
= newtmp("abi", Kl
, fn
);
700 r1
= newtmp("abi", Kl
, fn
);
701 emit(Ostorel
, Kw
, R
, r1
, r0
);
702 emit(Oadd
, Kl
, r1
, rsave
, getcon(64, fn
));
703 emit(Oadd
, Kl
, r0
, ap
, getcon(8, 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(192, fn
));
709 emit(Oaddr
, Kl
, rsave
, SLOT(-1), R
);
710 emit(Oadd
, Kl
, r0
, ap
, getcon(16, fn
));
712 r0
= newtmp("abi", Kl
, fn
);
713 emit(Ostorew
, Kw
, R
, getcon((p
.ngp
-8)*8, fn
), r0
);
714 emit(Oadd
, Kl
, r0
, ap
, getcon(24, fn
));
716 r0
= newtmp("abi", Kl
, fn
);
717 emit(Ostorew
, Kw
, R
, getcon((p
.nfp
-8)*16, fn
), r0
);
718 emit(Oadd
, Kl
, r0
, ap
, getcon(28, fn
));
730 for (b
=fn
->start
; b
; b
=b
->link
)
733 /* lower parameters */
734 for (b
=fn
->start
, i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
737 p
= selpar(fn
, b
->ins
, i
);
738 n
= b
->nins
- (i
- b
->ins
) + (&insb
[NIns
] - curi
);
739 i0
= alloc(n
* sizeof(Ins
));
740 ip
= icpy(ip
= i0
, curi
, &insb
[NIns
] - curi
);
741 ip
= icpy(ip
, i
, &b
->ins
[b
->nins
] - i
);
745 /* lower calls, returns, and vararg instructions */
750 b
= fn
->start
; /* do it last */
755 for (i
=&b
->ins
[b
->nins
]; i
!=b
->ins
;)
761 for (i0
=i
; i0
>b
->ins
; i0
--)
762 if (!isarg((i0
-1)->op
))
764 selcall(fn
, i0
, i
, &il
);
769 apple_selvastart(fn
, p
, i
->arg
[0]);
771 arm64_selvastart(fn
, p
, i
->arg
[0]);
775 apple_selvaarg(fn
, b
, i
);
777 arm64_selvaarg(fn
, b
, i
);
784 for (; il
; il
=il
->link
)
786 b
->nins
= &insb
[NIns
] - curi
;
787 idup(&b
->ins
, curi
, b
->nins
);
788 } while (b
!= fn
->start
);
791 fprintf(stderr
, "\n> After ABI lowering:\n");
796 /* abi0 for apple target; introduces
797 * necessery sign extension for arg
808 for (b
=fn
->start
; b
; b
=b
->link
) {
812 r
= newtmp("abi", Kw
, fn
);
813 op
= Oextsb
+ (j
- Jretsb
);
814 emit(op
, Kw
, r
, b
->jmp
.arg
, R
);
817 for (i
=&b
->ins
[b
->nins
]; i
>b
->ins
;) {
821 for (i0
=i1
=i
; i0
>b
->ins
; i0
--)
822 if (!isarg((i0
-1)->op
))
826 if (isargbh(i
->op
)) {
827 i
->to
= newtmp("abi", Kl
, fn
);
828 curi
->arg
[0] = i
->to
;
832 if (isargbh((--i
)->op
)) {
833 op
= Oextsb
+ (i
->op
- Oargsb
);
834 emit(op
, Kw
, i
->to
, i
->arg
[0], R
);
837 b
->nins
= &insb
[NIns
] - curi
;
838 idup(&b
->ins
, curi
, b
->nins
);
842 fprintf(stderr
, "\n> After apple_extsb:\n");