33 Ki
= -1, /* matches Kw and Kl */
34 Ka
= -2, /* matches all classes */
42 { Oadd
, Ki
, "add %=, %0, %1" },
43 { Oadd
, Ka
, "fadd %=, %0, %1" },
44 { Osub
, Ki
, "sub %=, %0, %1" },
45 { Osub
, Ka
, "fsub %=, %0, %1" },
46 { Oneg
, Ki
, "neg %=, %0" },
47 { Oneg
, Ka
, "fneg %=, %0" },
48 { Oand
, Ki
, "and %=, %0, %1" },
49 { Oor
, Ki
, "orr %=, %0, %1" },
50 { Oxor
, Ki
, "eor %=, %0, %1" },
51 { Osar
, Ki
, "asr %=, %0, %1" },
52 { Oshr
, Ki
, "lsr %=, %0, %1" },
53 { Oshl
, Ki
, "lsl %=, %0, %1" },
54 { Omul
, Ki
, "mul %=, %0, %1" },
55 { Omul
, Ka
, "fmul %=, %0, %1" },
56 { Odiv
, Ki
, "sdiv %=, %0, %1" },
57 { Odiv
, Ka
, "fdiv %=, %0, %1" },
58 { Oudiv
, Ki
, "udiv %=, %0, %1" },
59 { Orem
, Ki
, "sdiv %?, %0, %1\n\tmsub\t%=, %?, %1, %0" },
60 { Ourem
, Ki
, "udiv %?, %0, %1\n\tmsub\t%=, %?, %1, %0" },
61 { Ocopy
, Ki
, "mov %=, %0" },
62 { Ocopy
, Ka
, "fmov %=, %0" },
63 { Oswap
, Ki
, "mov %?, %0\n\tmov\t%0, %1\n\tmov\t%1, %?" },
64 { Oswap
, Ka
, "fmov %?, %0\n\tfmov\t%0, %1\n\tfmov\t%1, %?" },
65 { Ostoreb
, Kw
, "strb %W0, %M1" },
66 { Ostoreh
, Kw
, "strh %W0, %M1" },
67 { Ostorew
, Kw
, "str %W0, %M1" },
68 { Ostorel
, Kw
, "str %L0, %M1" },
69 { Ostores
, Kw
, "str %S0, %M1" },
70 { Ostored
, Kw
, "str %D0, %M1" },
71 { Oloadsb
, Ki
, "ldrsb %=, %M0" },
72 { Oloadub
, Ki
, "ldrb %W=, %M0" },
73 { Oloadsh
, Ki
, "ldrsh %=, %M0" },
74 { Oloaduh
, Ki
, "ldrh %W=, %M0" },
75 { Oloadsw
, Kw
, "ldr %=, %M0" },
76 { Oloadsw
, Kl
, "ldrsw %=, %M0" },
77 { Oloaduw
, Ki
, "ldr %W=, %M0" },
78 { Oload
, Ka
, "ldr %=, %M0" },
79 { Oextsb
, Ki
, "sxtb %=, %W0" },
80 { Oextub
, Ki
, "uxtb %W=, %W0" },
81 { Oextsh
, Ki
, "sxth %=, %W0" },
82 { Oextuh
, Ki
, "uxth %W=, %W0" },
83 { Oextsw
, Ki
, "sxtw %L=, %W0" },
84 { Oextuw
, Ki
, "mov %W=, %W0" },
85 { Oexts
, Kd
, "fcvt %=, %S0" },
86 { Otruncd
, Ks
, "fcvt %=, %D0" },
87 { Ocast
, Kw
, "fmov %=, %S0" },
88 { Ocast
, Kl
, "fmov %=, %D0" },
89 { Ocast
, Ks
, "fmov %=, %W0" },
90 { Ocast
, Kd
, "fmov %=, %L0" },
91 { Ostosi
, Ka
, "fcvtzs %=, %S0" },
92 { Ostoui
, Ka
, "fcvtzu %=, %S0" },
93 { Odtosi
, Ka
, "fcvtzs %=, %D0" },
94 { Odtoui
, Ka
, "fcvtzu %=, %D0" },
95 { Oswtof
, Ka
, "scvtf %=, %W0" },
96 { Ouwtof
, Ka
, "ucvtf %=, %W0" },
97 { Osltof
, Ka
, "scvtf %=, %L0" },
98 { Oultof
, Ka
, "ucvtf %=, %L0" },
99 { Ocall
, Kw
, "blr %L0" },
101 { Oacmp
, Ki
, "cmp %0, %1" },
102 { Oacmn
, Ki
, "cmn %0, %1" },
103 { Oafcmp
, Ka
, "fcmpe %0, %1" },
106 { Oflag+c, Ki, "cset %=, " str },
121 else if (R0
<= r
&& r
<= LR
)
123 default: die("invalid class");
124 case Kw
: sprintf(buf
, "w%d", r
-R0
); break;
126 case Kl
: sprintf(buf
, "x%d", r
-R0
); break;
128 else if (V0
<= r
&& r
<= V30
)
130 default: die("invalid class");
131 case Ks
: sprintf(buf
, "s%d", r
-V0
); break;
133 case Kd
: sprintf(buf
, "d%d", r
-V0
); break;
136 die("invalid register");
143 s
= ((int32_t)s
<< 3) >> 3;
145 return 16 + e
->frame
;
147 if (e
->fn
->vararg
&& !T
.apple
)
148 return 16 + e
->frame
+ 192 - (s
+2);
150 return 16 + e
->frame
- (s
+2);
152 return 16 + e
->padding
+ 4 * s
;
156 emitf(char *s
, Ins
*i
, E
*e
)
168 while ((c
= *s
++) != '%')
169 if (c
== ' ' && !sp
) {
178 switch ((c
= *s
++)) {
180 die("invalid escape");
195 fputs(rname(R18
, k
), e
->f
);
197 fputs(k
==Ks
? "s31" : "d31", e
->f
);
201 r
= c
== '=' ? i
->to
: i
->arg
[0];
203 fputs(rname(r
.val
, k
), e
->f
);
209 die("invalid second argument");
212 fputs(rname(r
.val
, k
), e
->f
);
215 pc
= &e
->fn
->con
[r
.val
];
217 assert(pc
->type
== CBits
);
219 fprintf(e
->f
, "#%u, lsl #12", n
>>12);
221 fprintf(e
->f
, "#%u", n
);
227 assert(c
== '0' || c
== '1' || c
== '=');
228 r
= c
== '=' ? i
->to
: i
->arg
[c
- '0'];
231 die("todo (arm emit): unhandled ref");
234 fprintf(e
->f
, "[%s]", rname(r
.val
, Kl
));
237 fprintf(e
->f
, "[x29, %"PRIu64
"]", slot(r
.val
, e
));
246 loadaddr(Con
*c
, char *rn
, E
*e
)
250 switch (c
->sym
.type
) {
255 s
= "\tadrp\tR, S@pageO\n"
256 "\tadd\tR, R, S@pageoffO\n";
258 s
= "\tadrp\tR, SO\n"
259 "\tadd\tR, R, #:lo12:SO\n";
263 s
= "\tadrp\tR, S@tlvppage\n"
264 "\tldr\tR, [R, S@tlvppageoff]\n";
266 s
= "\tmrs\tR, tpidr_el0\n"
267 "\tadd\tR, R, #:tprel_hi12:SO, lsl #12\n"
268 "\tadd\tR, R, #:tprel_lo12_nc:SO\n";
273 p
= l
[0] == '"' ? "" : T
.assym
;
288 /* todo, handle large offsets */
289 fprintf(e
->f
, "+%"PRIi64
, c
->bits
.i
);
295 loadcon(Con
*c
, int r
, int k
, E
*e
)
304 if (c
->type
== CAddr
) {
308 assert(c
->type
== CBits
);
311 if ((n
| 0xffff) == -1 || arm64_logimm(n
, k
)) {
312 fprintf(e
->f
, "\tmov\t%s, #%"PRIi64
"\n", rn
, n
);
314 fprintf(e
->f
, "\tmov\t%s, #%d\n",
315 rn
, (int)(n
& 0xffff));
316 for (sh
=16; n
>>=16; sh
+=16) {
317 if ((!w
&& sh
== 32) || sh
== 64)
319 fprintf(e
->f
, "\tmovk\t%s, #0x%x, lsl #%d\n",
320 rn
, (uint
)(n
& 0xffff), sh
);
325 static void emitins(Ins
*, E
*);
328 fixarg(Ref
*pr
, int sz
, E
*e
)
335 if (rtype(r
) == RSlot
) {
337 if (s
> sz
* 4095u) {
338 i
= &(Ins
){Oaddr
, Kl
, TMP(IP0
), {r
}};
346 emitins(Ins
*i
, E
*e
)
357 fixarg(&i
->arg
[0], loadsz(i
), e
);
359 fixarg(&i
->arg
[1], storesz(i
), e
);
361 /* most instructions are just pulled out of
362 * the table omap[], some special cases are
365 /* this linear search should really be a binary
367 if (omap
[o
].op
== NOp
)
368 die("no match for %s(%c)",
369 optab
[i
->op
].name
, "wlsd"[i
->cls
]);
370 if (omap
[o
].op
== i
->op
)
371 if (omap
[o
].cls
== i
->cls
|| omap
[o
].cls
== Ka
372 || (omap
[o
].cls
== Ki
&& KBASE(i
->cls
) == 0))
375 emitf(omap
[o
].asm, i
, e
);
380 if (req(i
->to
, i
->arg
[0]))
382 if (rtype(i
->to
) == RSlot
) {
384 if (!isreg(i
->arg
[0])) {
389 i
->op
= Ostorew
+ i
->cls
;
395 assert(isreg(i
->to
));
396 switch (rtype(i
->arg
[0])) {
398 c
= &e
->fn
->con
[i
->arg
[0].val
];
399 loadcon(c
, i
->to
.val
, i
->cls
, e
);
406 assert(i
->to
.val
!= R18
);
411 assert(rtype(i
->arg
[0]) == RSlot
);
412 rn
= rname(i
->to
.val
, Kl
);
413 s
= slot(i
->arg
[0].val
, e
);
415 fprintf(e
->f
, "\tadd\t%s, x29, #%"PRIu64
"\n", rn
, s
);
418 "\tmov\t%s, #%"PRIu64
"\n"
419 "\tadd\t%s, x29, %s\n",
424 "\tmov\t%s, #%"PRIu64
"\n"
425 "\tmovk\t%s, #%"PRIu64
", lsl #16\n"
426 "\tadd\t%s, x29, %s\n",
427 rn
, s
& 0xFFFF, rn
, s
>> 16, rn
, rn
431 if (rtype(i
->arg
[0]) != RCon
)
433 c
= &e
->fn
->con
[i
->arg
[0].val
];
435 || c
->sym
.type
!= SGlo
437 die("invalid call argument");
439 p
= l
[0] == '"' ? "" : T
.assym
;
440 fprintf(e
->f
, "\tbl\t%s%s\n", p
, l
);
443 emitf("sub sp, sp, %0", i
, e
);
445 emitf("mov %=, sp", i
, e
);
457 for (o
=0, r
=arm64_rclob
; *r
>=0; r
++)
458 o
+= 1 & (e
->fn
->reg
>> *r
);
462 e
->padding
= 4*(f
-e
->fn
->slot
);
463 e
->frame
= 4*f
+ 8*o
;
489 +=============+ <- x29
494 arm64_emitfn(Fn
*fn
, FILE *out
)
496 static char *ctoa
[] = {
497 #define X(c, s) [c] = s,
502 int s
, n
, c
, lbl
, *r
;
508 e
= &(E
){.f
= out
, .fn
= fn
};
510 e
->fn
->lnk
.align
= 4;
511 emitfnlnk(e
->fn
->name
, &e
->fn
->lnk
, e
->f
);
514 if (e
->fn
->vararg
&& !T
.apple
) {
516 fprintf(e
->f
, "\tstr\tq%d, [sp, -16]!\n", n
);
517 for (n
=7; n
>=0; n
-=2)
518 fprintf(e
->f
, "\tstp\tx%d, x%d, [sp, -16]!\n", n
-1, n
);
521 if (e
->frame
+ 16 <= 512)
523 "\tstp\tx29, x30, [sp, -%"PRIu64
"]!\n",
526 else if (e
->frame
<= 4095)
528 "\tsub\tsp, sp, #%"PRIu64
"\n"
529 "\tstp\tx29, x30, [sp, -16]!\n",
532 else if (e
->frame
<= 65535)
534 "\tmov\tx16, #%"PRIu64
"\n"
535 "\tsub\tsp, sp, x16\n"
536 "\tstp\tx29, x30, [sp, -16]!\n",
541 "\tmov\tx16, #%"PRIu64
"\n"
542 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
543 "\tsub\tsp, sp, x16\n"
544 "\tstp\tx29, x30, [sp, -16]!\n",
545 e
->frame
& 0xFFFF, e
->frame
>> 16
547 fputs("\tmov\tx29, sp\n", e
->f
);
548 s
= (e
->frame
- e
->padding
) / 4;
549 for (r
=arm64_rclob
; *r
>=0; r
++)
550 if (e
->fn
->reg
& BIT(*r
)) {
552 i
= &(Ins
){.arg
= {TMP(*r
), SLOT(s
)}};
553 i
->op
= *r
>= V0
? Ostored
: Ostorel
;
557 for (lbl
=0, b
=e
->fn
->start
; b
; b
=b
->link
) {
558 if (lbl
|| b
->npred
> 1)
559 fprintf(e
->f
, "%s%d:\n", T
.asloc
, id0
+b
->id
);
560 for (i
=b
->ins
; i
!=&b
->ins
[b
->nins
]; i
++)
563 switch (b
->jmp
.type
) {
565 s
= (e
->frame
- e
->padding
) / 4;
566 for (r
=arm64_rclob
; *r
>=0; r
++)
567 if (e
->fn
->reg
& BIT(*r
)) {
569 i
= &(Ins
){Oload
, 0, TMP(*r
), {SLOT(s
)}};
570 i
->cls
= *r
>= V0
? Kd
: Kl
;
574 fputs("\tmov sp, x29\n", e
->f
);
576 if (e
->fn
->vararg
&& !T
.apple
)
580 "\tldp\tx29, x30, [sp], %"PRIu64
"\n",
583 else if (o
- 16 <= 4095)
585 "\tldp\tx29, x30, [sp], 16\n"
586 "\tadd\tsp, sp, #%"PRIu64
"\n",
589 else if (o
- 16 <= 65535)
591 "\tldp\tx29, x30, [sp], 16\n"
592 "\tmov\tx16, #%"PRIu64
"\n"
593 "\tadd\tsp, sp, x16\n",
598 "\tldp\tx29, x30, [sp], 16\n"
599 "\tmov\tx16, #%"PRIu64
"\n"
600 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
601 "\tadd\tsp, sp, x16\n",
602 (o
- 16) & 0xFFFF, (o
- 16) >> 16
604 fprintf(e
->f
, "\tret\n");
608 if (b
->s1
!= b
->link
)
611 T
.asloc
, id0
+b
->s1
->id
617 c
= b
->jmp
.type
- Jjf
;
618 if (c
< 0 || c
> NCmp
)
619 die("unhandled jump %d", b
->jmp
.type
);
620 if (b
->link
== b
->s2
) {
628 ctoa
[c
], T
.asloc
, id0
+b
->s2
->id