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");
147 return 16 + e
->frame
;
149 if (e
->fn
->vararg
&& !T
.apple
)
150 return 16 + e
->frame
+ 192 - (s
+2);
152 return 16 + e
->frame
- (s
+2);
154 return 16 + e
->padding
+ 4 * s
;
158 emitf(char *s
, Ins
*i
, E
*e
)
171 while ((c
= *s
++) != '%')
172 if (c
== ' ' && !sp
) {
181 switch ((c
= *s
++)) {
183 die("invalid escape");
198 fputs(rname(R18
, k
), e
->f
);
200 fputs(k
==Ks
? "s31" : "d31", e
->f
);
204 r
= c
== '=' ? i
->to
: i
->arg
[0];
206 fputs(rname(r
.val
, k
), e
->f
);
212 die("invalid second argument");
215 fputs(rname(r
.val
, k
), e
->f
);
218 pc
= &e
->fn
->con
[r
.val
];
220 assert(pc
->type
== CBits
);
222 assert(arm64_logimm(n
, k
));
223 fprintf(e
->f
, "#%"PRIu64
, n
);
224 } else if (n
& 0xfff000) {
225 assert(!(n
& ~0xfff000ull
));
226 fprintf(e
->f
, "#%"PRIu64
", lsl #12",
229 assert(!(n
& ~0xfffull
));
230 fprintf(e
->f
, "#%"PRIu64
, n
);
237 assert(c
== '0' || c
== '1' || c
== '=');
238 r
= c
== '=' ? i
->to
: i
->arg
[c
- '0'];
241 die("todo (arm emit): unhandled ref");
244 fprintf(e
->f
, "[%s]", rname(r
.val
, Kl
));
247 fprintf(e
->f
, "[x29, %"PRIu64
"]", slot(r
, e
));
256 loadaddr(Con
*c
, char *rn
, E
*e
)
260 switch (c
->sym
.type
) {
265 s
= "\tadrp\tR, S@pageO\n"
266 "\tadd\tR, R, S@pageoffO\n";
268 s
= "\tadrp\tR, SO\n"
269 "\tadd\tR, R, #:lo12:SO\n";
273 s
= "\tadrp\tR, S@tlvppage\n"
274 "\tldr\tR, [R, S@tlvppageoff]\n";
276 s
= "\tmrs\tR, tpidr_el0\n"
277 "\tadd\tR, R, #:tprel_hi12:SO, lsl #12\n"
278 "\tadd\tR, R, #:tprel_lo12_nc:SO\n";
283 p
= l
[0] == '"' ? "" : T
.assym
;
298 /* todo, handle large offsets */
299 fprintf(e
->f
, "+%"PRIi64
, c
->bits
.i
);
305 loadcon(Con
*c
, int r
, int k
, E
*e
)
314 if (c
->type
== CAddr
) {
319 assert(c
->type
== CBits
);
322 if ((n
| 0xffff) == -1 || arm64_logimm(n
, k
)) {
323 fprintf(e
->f
, "\tmov\t%s, #%"PRIi64
"\n", rn
, n
);
325 fprintf(e
->f
, "\tmov\t%s, #%d\n",
326 rn
, (int)(n
& 0xffff));
327 for (sh
=16; n
>>=16; sh
+=16) {
328 if ((!w
&& sh
== 32) || sh
== 64)
330 fprintf(e
->f
, "\tmovk\t%s, #0x%x, lsl #%d\n",
331 rn
, (uint
)(n
& 0xffff), sh
);
336 static void emitins(Ins
*, E
*);
339 fixarg(Ref
*pr
, int sz
, E
*e
)
346 if (rtype(r
) == RSlot
) {
348 if (s
> sz
* 4095u) {
349 i
= &(Ins
){Oaddr
, Kl
, TMP(IP0
), {r
}};
357 emitins(Ins
*i
, E
*e
)
368 fixarg(&i
->arg
[0], loadsz(i
), e
);
370 fixarg(&i
->arg
[1], storesz(i
), e
);
372 /* most instructions are just pulled out of
373 * the table omap[], some special cases are
376 /* this linear search should really be a binary
378 if (omap
[o
].op
== NOp
)
379 die("no match for %s(%c)",
380 optab
[i
->op
].name
, "wlsd"[i
->cls
]);
381 if (omap
[o
].op
== i
->op
)
382 if (omap
[o
].cls
== i
->cls
|| omap
[o
].cls
== Ka
383 || (omap
[o
].cls
== Ki
&& KBASE(i
->cls
) == 0))
386 emitf(omap
[o
].fmt
, i
, e
);
391 if (req(i
->to
, i
->arg
[0]))
393 if (rtype(i
->to
) == RSlot
) {
395 if (!isreg(i
->arg
[0])) {
400 i
->op
= Ostorew
+ i
->cls
;
406 assert(isreg(i
->to
));
407 switch (rtype(i
->arg
[0])) {
409 c
= &e
->fn
->con
[i
->arg
[0].val
];
410 loadcon(c
, i
->to
.val
, i
->cls
, e
);
417 assert(i
->to
.val
!= R18
);
422 assert(rtype(i
->arg
[0]) == RSlot
);
423 rn
= rname(i
->to
.val
, Kl
);
424 s
= slot(i
->arg
[0], e
);
426 fprintf(e
->f
, "\tadd\t%s, x29, #%"PRIu64
"\n", rn
, s
);
429 "\tmov\t%s, #%"PRIu64
"\n"
430 "\tadd\t%s, x29, %s\n",
435 "\tmov\t%s, #%"PRIu64
"\n"
436 "\tmovk\t%s, #%"PRIu64
", lsl #16\n"
437 "\tadd\t%s, x29, %s\n",
438 rn
, s
& 0xFFFF, rn
, s
>> 16, rn
, rn
442 if (rtype(i
->arg
[0]) != RCon
)
444 c
= &e
->fn
->con
[i
->arg
[0].val
];
446 || c
->sym
.type
!= SGlo
448 die("invalid call argument");
450 p
= l
[0] == '"' ? "" : T
.assym
;
451 fprintf(e
->f
, "\tbl\t%s%s\n", p
, l
);
454 emitf("sub sp, sp, %0", i
, e
);
456 emitf("mov %=, sp", i
, e
);
459 emitdbgloc(i
->arg
[0].val
, i
->arg
[1].val
, e
->f
);
471 for (o
=0, r
=arm64_rclob
; *r
>=0; r
++)
472 o
+= 1 & (e
->fn
->reg
>> *r
);
476 e
->padding
= 4*(f
-e
->fn
->slot
);
477 e
->frame
= 4*f
+ 8*o
;
503 +=============+ <- x29
508 arm64_emitfn(Fn
*fn
, FILE *out
)
510 static char *ctoa
[] = {
511 #define X(c, s) [c] = s,
516 int s
, n
, c
, lbl
, *r
;
522 e
= &(E
){.f
= out
, .fn
= fn
};
524 e
->fn
->lnk
.align
= 4;
525 emitfnlnk(e
->fn
->name
, &e
->fn
->lnk
, e
->f
);
526 fputs("\thint\t#34\n", e
->f
);
529 if (e
->fn
->vararg
&& !T
.apple
) {
531 fprintf(e
->f
, "\tstr\tq%d, [sp, -16]!\n", n
);
532 for (n
=7; n
>=0; n
-=2)
533 fprintf(e
->f
, "\tstp\tx%d, x%d, [sp, -16]!\n", n
-1, n
);
536 if (e
->frame
+ 16 <= 512)
538 "\tstp\tx29, x30, [sp, -%"PRIu64
"]!\n",
541 else if (e
->frame
<= 4095)
543 "\tsub\tsp, sp, #%"PRIu64
"\n"
544 "\tstp\tx29, x30, [sp, -16]!\n",
547 else if (e
->frame
<= 65535)
549 "\tmov\tx16, #%"PRIu64
"\n"
550 "\tsub\tsp, sp, x16\n"
551 "\tstp\tx29, x30, [sp, -16]!\n",
556 "\tmov\tx16, #%"PRIu64
"\n"
557 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
558 "\tsub\tsp, sp, x16\n"
559 "\tstp\tx29, x30, [sp, -16]!\n",
560 e
->frame
& 0xFFFF, e
->frame
>> 16
562 fputs("\tmov\tx29, sp\n", e
->f
);
563 s
= (e
->frame
- e
->padding
) / 4;
564 for (r
=arm64_rclob
; *r
>=0; r
++)
565 if (e
->fn
->reg
& BIT(*r
)) {
567 i
= &(Ins
){.arg
= {TMP(*r
), SLOT(s
)}};
568 i
->op
= *r
>= V0
? Ostored
: Ostorel
;
572 for (lbl
=0, b
=e
->fn
->start
; b
; b
=b
->link
) {
573 if (lbl
|| b
->npred
> 1)
574 fprintf(e
->f
, "%s%d:\n", T
.asloc
, id0
+b
->id
);
575 for (i
=b
->ins
; i
!=&b
->ins
[b
->nins
]; i
++)
578 switch (b
->jmp
.type
) {
580 fprintf(e
->f
, "\tbrk\t#1000\n");
583 s
= (e
->frame
- e
->padding
) / 4;
584 for (r
=arm64_rclob
; *r
>=0; r
++)
585 if (e
->fn
->reg
& BIT(*r
)) {
587 i
= &(Ins
){Oload
, 0, TMP(*r
), {SLOT(s
)}};
588 i
->cls
= *r
>= V0
? Kd
: Kl
;
592 fputs("\tmov sp, x29\n", e
->f
);
594 if (e
->fn
->vararg
&& !T
.apple
)
598 "\tldp\tx29, x30, [sp], %"PRIu64
"\n",
601 else if (o
- 16 <= 4095)
603 "\tldp\tx29, x30, [sp], 16\n"
604 "\tadd\tsp, sp, #%"PRIu64
"\n",
607 else if (o
- 16 <= 65535)
609 "\tldp\tx29, x30, [sp], 16\n"
610 "\tmov\tx16, #%"PRIu64
"\n"
611 "\tadd\tsp, sp, x16\n",
616 "\tldp\tx29, x30, [sp], 16\n"
617 "\tmov\tx16, #%"PRIu64
"\n"
618 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
619 "\tadd\tsp, sp, x16\n",
620 (o
- 16) & 0xFFFF, (o
- 16) >> 16
622 fprintf(e
->f
, "\tret\n");
626 if (b
->s1
!= b
->link
)
629 T
.asloc
, id0
+b
->s1
->id
635 c
= b
->jmp
.type
- Jjf
;
636 if (c
< 0 || c
> NCmp
)
637 die("unhandled jump %d", b
->jmp
.type
);
638 if (b
->link
== b
->s2
) {
646 ctoa
[c
], T
.asloc
, id0
+b
->s2
->id
653 elf_emitfnfin(fn
->name
, out
);