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)
45 * |0.00|x|xxxx|xxxx|xxx|xx| range
46 * | | | | ` gp regs returned (0..2)
47 * | | | ` fp regs returned (0..4)
48 * | | ` gp regs passed (0..8)
49 * | ` fp regs passed (0..8)
54 isfloatv(Typ
*t
, char *cls
)
59 for (n
=0; n
<t
->nunion
; n
++)
60 for (f
=t
->fields
[n
]; f
->type
!= FEnd
; f
++)
73 if (isfloatv(&typ
[f
->len
], cls
))
83 typclass(Class
*c
, Typ
*t
, int *gp
, int *fp
)
88 sz
= (t
->size
+ 7) & -8;
95 err("alignments larger than 16 are not supported");
97 if (t
->isdark
|| sz
> 16 || sz
== 0) {
98 /* large structs are replaced by a
99 * pointer to some caller-allocated
108 c
->ishfa
= isfloatv(t
, &c
->hfa
.base
);
109 c
->hfa
.size
= t
->size
/(KWIDE(c
->hfa
.base
) ? 8 : 4);
112 for (n
=0; n
<c
->hfa
.size
; n
++, c
->nfp
++) {
114 c
->cls
[n
] = c
->hfa
.base
;
117 for (n
=0; n
<sz
/8; n
++, c
->ngp
++) {
126 sttmps(Ref tmp
[], int cls
[], uint nreg
, Ref mem
, Fn
*fn
)
129 [Kw
] = Ostorew
, [Kl
] = Ostorel
,
130 [Ks
] = Ostores
, [Kd
] = Ostored
138 for (n
=0; n
<nreg
; n
++) {
139 tmp
[n
] = newtmp("abi", cls
[n
], fn
);
140 r
= newtmp("abi", Kl
, fn
);
141 emit(st
[cls
[n
]], 0, R
, tmp
[n
], r
);
142 emit(Oadd
, Kl
, r
, mem
, getcon(off
, fn
));
143 off
+= KWIDE(cls
[n
]) ? 8 : 4;
147 /* todo, may read out of bounds */
149 ldregs(int reg
[], int cls
[], int n
, Ref mem
, Fn
*fn
)
156 for (i
=0; i
<n
; i
++) {
157 r
= newtmp("abi", Kl
, fn
);
158 emit(Oload
, cls
[i
], TMP(reg
[i
]), r
, R
);
159 emit(Oadd
, Kl
, r
, mem
, getcon(off
, fn
));
160 off
+= KWIDE(cls
[i
]) ? 8 : 4;
165 selret(Blk
*b
, Fn
*fn
)
173 if (!isret(j
) || j
== Jret0
)
180 typclass(&cr
, &typ
[fn
->retty
], gpreg
, fpreg
);
181 cty
= (cr
.nfp
<< 2) | cr
.ngp
;
182 if (cr
.class & Cptr
) {
183 assert(rtype(fn
->retr
) == RTmp
);
184 blit0(fn
->retr
, r
, cr
.t
->size
, fn
);
186 ldregs(cr
.reg
, cr
.cls
, cr
.nreg
, r
, fn
);
190 emit(Ocopy
, k
, TMP(R0
), r
, R
);
193 emit(Ocopy
, k
, TMP(V0
), r
, R
);
198 b
->jmp
.arg
= CALL(cty
);
202 argsclass(Ins
*i0
, Ins
*i1
, Class
*carg
, Ref
*env
)
204 int ngp
, nfp
, *gp
, *fp
;
212 for (i
=i0
, c
=carg
; i
<i1
; i
++, c
++)
218 if (KBASE(i
->cls
) == 0 && ngp
> 0) {
223 if (KBASE(i
->cls
) == 1 && nfp
> 0) {
232 typclass(c
, &typ
[i
->arg
[0].val
], gp
, fp
);
233 if (c
->class & Cptr
) {
240 } else if (c
->ngp
<= ngp
) {
265 return ((gp
-gpreg
) << 5) | ((fp
-fpreg
) << 9);
269 arm64_retregs(Ref r
, int p
[2])
274 assert(rtype(r
) == RCall
);
276 nfp
= (r
.val
>> 2) & 7;
290 arm64_argregs(Ref r
, int p
[2])
295 assert(rtype(r
) == RCall
);
296 ngp
= (r
.val
>> 5) & 15;
297 nfp
= (r
.val
>> 9) & 15;
298 x8
= (r
.val
>> 13) & 1;
308 return b
| ((bits
)x8
<< R8
);
312 stkblob(Ref r
, Class
*c
, Fn
*fn
, Insl
**ilp
)
318 il
= alloc(sizeof *il
);
319 al
= c
->t
->align
- 2; /* NAlign == 3 */
322 sz
= c
->class & Cptr
? c
->t
->size
: c
->size
;
323 il
->i
= (Ins
){Oalloc
+al
, Kl
, r
, {getcon(sz
, fn
)}};
329 selcall(Fn
*fn
, Ins
*i0
, Ins
*i1
, Insl
**ilp
)
336 Ref r
, rstk
, env
, tmp
[4];
339 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
340 cty
= argsclass(i0
, i1
, ca
, &env
);
343 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
344 if (c
->class & Cptr
) {
345 i
->arg
[0] = newtmp("abi", Kl
, fn
);
346 stkblob(i
->arg
[0], c
, fn
, ilp
);
353 rstk
= getcon(stk
, fn
);
355 emit(Oadd
, Kl
, TMP(SP
), TMP(SP
), rstk
);
357 if (!req(i1
->arg
[1], R
)) {
358 typclass(&cr
, &typ
[i1
->arg
[1].val
], gpreg
, fpreg
);
359 stkblob(i1
->to
, &cr
, fn
, ilp
);
360 cty
|= (cr
.nfp
<< 2) | cr
.ngp
;
361 if (cr
.class & Cptr
) {
362 /* spill & rega expect calls to be
363 * followed by copies from regs,
367 emit(Ocopy
, Kw
, R
, TMP(R0
), R
);
369 sttmps(tmp
, cr
.cls
, cr
.nreg
, i1
->to
, fn
);
370 for (n
=0; n
<cr
.nreg
; n
++) {
372 emit(Ocopy
, cr
.cls
[n
], tmp
[n
], r
, R
);
376 if (KBASE(i1
->cls
) == 0) {
377 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(R0
), R
);
380 emit(Ocopy
, i1
->cls
, i1
->to
, TMP(V0
), R
);
385 emit(Ocall
, 0, R
, i1
->arg
[0], CALL(cty
));
389 die("todo: env calls");
392 /* struct return argument */
393 emit(Ocopy
, Kl
, TMP(R8
), i1
->to
, R
);
395 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
396 if ((c
->class & Cstk
) != 0)
399 emit(Ocopy
, *c
->cls
, TMP(*c
->reg
), i
->arg
[0], R
);
401 ldregs(c
->reg
, c
->cls
, c
->nreg
, i
->arg
[1], fn
);
405 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
406 if ((c
->class & Cstk
) == 0)
409 r
= newtmp("abi", Kl
, fn
);
410 emit(Ostorel
, 0, R
, i
->arg
[0], r
);
411 emit(Oadd
, Kl
, r
, TMP(SP
), getcon(off
, fn
));
414 blit(TMP(SP
), off
, i
->arg
[1], 0, c
->size
, fn
);
418 emit(Osub
, Kl
, TMP(SP
), TMP(SP
), rstk
);
420 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++)
422 blit0(i
->arg
[0], i
->arg
[1], c
->t
->size
, fn
);
426 selpar(Fn
*fn
, Ins
*i0
, Ins
*i1
)
432 Ref r
, env
, tmp
[16], *t
;
435 ca
= alloc((i1
-i0
) * sizeof ca
[0]);
438 cty
= argsclass(i0
, i1
, ca
, &env
);
439 fn
->reg
= arm64_argregs(CALL(cty
), 0);
443 for (i
=i0
, c
=ca
; i
<i1
; i
++, c
++) {
444 if (i
->op
!= Oparc
|| (c
->class & (Cptr
|Cstk
)))
446 sttmps(t
, c
->cls
, c
->nreg
, i
->to
, fn
);
447 stkblob(i
->to
, c
, fn
, &il
);
450 for (; il
; il
=il
->link
)
453 if (fn
->retty
>= 0) {
454 typclass(&cr
, &typ
[fn
->retty
], gpreg
, fpreg
);
455 if (cr
.class & Cptr
) {
456 fn
->retr
= newtmp("abi", Kl
, fn
);
457 emit(Ocopy
, Kl
, fn
->retr
, TMP(R8
), R
);
463 for (i
=i0
, c
=ca
, s
=2; i
<i1
; i
++, c
++) {
465 && (c
->class & Cptr
) == 0) {
466 if (c
->class & Cstk
) {
467 fn
->tmp
[i
->to
.val
].slot
= -s
;
470 for (n
=0; n
<c
->nreg
; n
++) {
472 emit(Ocopy
, c
->cls
[n
], *t
++, r
, R
);
474 } else if (c
->class & Cstk
) {
475 r
= newtmp("abi", Kl
, fn
);
476 emit(Oload
, *c
->cls
, i
->to
, r
, R
);
477 emit(Oaddr
, Kl
, r
, SLOT(-s
), R
);
481 emit(Ocopy
, *c
->cls
, i
->to
, r
, R
);
486 die("todo: env calls");
490 .ngp
= (cty
>> 5) & 15,
491 .nfp
= (cty
>> 9) & 15
496 split(Fn
*fn
, Blk
*b
)
502 bn
->nins
= &insb
[NIns
] - curi
;
503 idup(&bn
->ins
, curi
, bn
->nins
);
505 bn
->visit
= ++b
->visit
;
506 (void)!snprintf(bn
->name
, NString
, "%s.%d", b
->name
, b
->visit
);
514 chpred(Blk
*b
, Blk
*bp
, Blk
*bp1
)
519 for (p
=b
->phi
; p
; p
=p
->link
) {
520 for (a
=0; p
->blk
[a
]!=bp
; a
++)
527 selvaarg(Fn
*fn
, Blk
*b
, Ins
*i
)
529 Ref loc
, lreg
, lstk
, nr
, r0
, r1
, c8
, c16
, c24
, c28
, ap
;
530 Blk
*b0
, *bstk
, *breg
;
534 c16
= getcon(16, fn
);
535 c24
= getcon(24, fn
);
536 c28
= getcon(28, fn
);
538 isgp
= KBASE(i
->cls
) == 0;
541 r0 =l add ap, (24 or 28)
546 r0 =l add ap, (8 or 16)
549 r0 =w add nr, (8 or 16)
550 r1 =l add ap, (24 or 28)
557 %loc =l phi @breg %lreg, @bstk %lstk
558 i->to =(i->cls) load %loc
561 loc
= newtmp("abi", Kl
, fn
);
562 emit(Oload
, i
->cls
, i
->to
, loc
, R
);
568 chpred(b
->s1
, b
, b0
);
569 if (b
->s2
&& b
->s2
!= b
->s1
)
570 chpred(b
->s2
, b
, b0
);
572 lreg
= newtmp("abi", Kl
, fn
);
573 nr
= newtmp("abi", Kl
, fn
);
574 r0
= newtmp("abi", Kw
, fn
);
575 r1
= newtmp("abi", Kl
, fn
);
576 emit(Ostorew
, Kw
, R
, r0
, r1
);
577 emit(Oadd
, Kl
, r1
, ap
, isgp
? c24
: c28
);
578 emit(Oadd
, Kw
, r0
, nr
, isgp
? c8
: c16
);
579 r0
= newtmp("abi", Kl
, fn
);
580 r1
= newtmp("abi", Kl
, fn
);
581 emit(Oadd
, Kl
, lreg
, r1
, nr
);
582 emit(Oload
, Kl
, r1
, r0
, R
);
583 emit(Oadd
, Kl
, r0
, ap
, isgp
? c8
: c16
);
585 breg
->jmp
.type
= Jjmp
;
588 lstk
= newtmp("abi", Kl
, fn
);
589 r0
= newtmp("abi", Kl
, fn
);
590 emit(Ostorel
, Kw
, R
, r0
, ap
);
591 emit(Oadd
, Kl
, r0
, lstk
, c8
);
592 emit(Oload
, Kl
, lstk
, ap
, R
);
594 bstk
->jmp
.type
= Jjmp
;
597 b0
->phi
= alloc(sizeof *b0
->phi
);
599 .cls
= Kl
, .to
= loc
,
601 .blk
= vnew(2, sizeof b0
->phi
->blk
[0], Pfn
),
602 .arg
= vnew(2, sizeof b0
->phi
->arg
[0], Pfn
),
604 b0
->phi
->blk
[0] = bstk
;
605 b0
->phi
->blk
[1] = breg
;
606 b0
->phi
->arg
[0] = lstk
;
607 b0
->phi
->arg
[1] = lreg
;
608 r0
= newtmp("abi", Kl
, fn
);
609 r1
= newtmp("abi", Kw
, fn
);
614 emit(Ocmpw
+Cislt
, Kw
, r1
, nr
, CON_Z
);
615 emit(Oloadsw
, Kl
, nr
, r0
, R
);
616 emit(Oadd
, Kl
, r0
, ap
, isgp
? c24
: c28
);
620 selvastart(Fn
*fn
, Params p
, Ref ap
)
624 rsave
= newtmp("abi", Kl
, fn
);
626 r0
= newtmp("abi", Kl
, fn
);
627 emit(Ostorel
, Kw
, R
, r0
, ap
);
628 emit(Oadd
, Kl
, r0
, rsave
, getcon(p
.nstk
*8 + 192, fn
));
630 r0
= newtmp("abi", Kl
, fn
);
631 r1
= newtmp("abi", Kl
, fn
);
632 emit(Ostorel
, Kw
, R
, r1
, r0
);
633 emit(Oadd
, Kl
, r1
, rsave
, getcon(64, fn
));
634 emit(Oadd
, Kl
, r0
, ap
, getcon(8, fn
));
636 r0
= newtmp("abi", Kl
, fn
);
637 r1
= newtmp("abi", Kl
, fn
);
638 emit(Ostorel
, Kw
, R
, r1
, r0
);
639 emit(Oadd
, Kl
, r1
, rsave
, getcon(192, fn
));
640 emit(Oaddr
, Kl
, rsave
, SLOT(-1), R
);
641 emit(Oadd
, Kl
, r0
, ap
, getcon(16, fn
));
643 r0
= newtmp("abi", Kl
, fn
);
644 emit(Ostorew
, Kw
, R
, getcon((p
.ngp
-8)*8, fn
), r0
);
645 emit(Oadd
, Kl
, r0
, ap
, getcon(24, fn
));
647 r0
= newtmp("abi", Kl
, fn
);
648 emit(Ostorew
, Kw
, R
, getcon((p
.nfp
-8)*16, fn
), r0
);
649 emit(Oadd
, Kl
, r0
, ap
, getcon(28, fn
));
661 for (b
=fn
->start
; b
; b
=b
->link
)
664 /* lower parameters */
665 for (b
=fn
->start
, i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
668 p
= selpar(fn
, b
->ins
, i
);
669 n
= b
->nins
- (i
- b
->ins
) + (&insb
[NIns
] - curi
);
670 i0
= alloc(n
* sizeof(Ins
));
671 ip
= icpy(ip
= i0
, curi
, &insb
[NIns
] - curi
);
672 ip
= icpy(ip
, i
, &b
->ins
[b
->nins
] - i
);
676 /* lower calls, returns, and vararg instructions */
681 b
= fn
->start
; /* do it last */
686 for (i
=&b
->ins
[b
->nins
]; i
!=b
->ins
;)
692 for (i0
=i
; i0
>b
->ins
; i0
--)
693 if (!isarg((i0
-1)->op
))
695 selcall(fn
, i0
, i
, &il
);
699 selvastart(fn
, p
, i
->arg
[0]);
709 for (; il
; il
=il
->link
)
711 b
->nins
= &insb
[NIns
] - curi
;
712 idup(&b
->ins
, curi
, b
->nins
);
713 } while (b
!= fn
->start
);
716 fprintf(stderr
, "\n> After ABI lowering:\n");