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
)
170 while ((c
= *s
++) != '%')
171 if (c
== ' ' && !sp
) {
180 switch ((c
= *s
++)) {
182 die("invalid escape");
197 fputs(rname(R18
, k
), e
->f
);
199 fputs(k
==Ks
? "s31" : "d31", e
->f
);
203 r
= c
== '=' ? i
->to
: i
->arg
[0];
205 fputs(rname(r
.val
, k
), e
->f
);
211 die("invalid second argument");
214 fputs(rname(r
.val
, k
), e
->f
);
217 pc
= &e
->fn
->con
[r
.val
];
219 assert(pc
->type
== CBits
);
221 fprintf(e
->f
, "#%u, lsl #12", n
>>12);
223 fprintf(e
->f
, "#%u", n
);
229 assert(c
== '0' || c
== '1' || c
== '=');
230 r
= c
== '=' ? i
->to
: i
->arg
[c
- '0'];
233 die("todo (arm emit): unhandled ref");
236 fprintf(e
->f
, "[%s]", rname(r
.val
, Kl
));
239 fprintf(e
->f
, "[x29, %"PRIu64
"]", slot(r
, e
));
248 loadaddr(Con
*c
, char *rn
, E
*e
)
252 switch (c
->sym
.type
) {
257 s
= "\tadrp\tR, S@pageO\n"
258 "\tadd\tR, R, S@pageoffO\n";
260 s
= "\tadrp\tR, SO\n"
261 "\tadd\tR, R, #:lo12:SO\n";
265 s
= "\tadrp\tR, S@tlvppage\n"
266 "\tldr\tR, [R, S@tlvppageoff]\n";
268 s
= "\tmrs\tR, tpidr_el0\n"
269 "\tadd\tR, R, #:tprel_hi12:SO, lsl #12\n"
270 "\tadd\tR, R, #:tprel_lo12_nc:SO\n";
275 p
= l
[0] == '"' ? "" : T
.assym
;
290 /* todo, handle large offsets */
291 fprintf(e
->f
, "+%"PRIi64
, c
->bits
.i
);
297 loadcon(Con
*c
, int r
, int k
, E
*e
)
306 if (c
->type
== CAddr
) {
310 assert(c
->type
== CBits
);
313 if ((n
| 0xffff) == -1 || arm64_logimm(n
, k
)) {
314 fprintf(e
->f
, "\tmov\t%s, #%"PRIi64
"\n", rn
, n
);
316 fprintf(e
->f
, "\tmov\t%s, #%d\n",
317 rn
, (int)(n
& 0xffff));
318 for (sh
=16; n
>>=16; sh
+=16) {
319 if ((!w
&& sh
== 32) || sh
== 64)
321 fprintf(e
->f
, "\tmovk\t%s, #0x%x, lsl #%d\n",
322 rn
, (uint
)(n
& 0xffff), sh
);
327 static void emitins(Ins
*, E
*);
330 fixarg(Ref
*pr
, int sz
, E
*e
)
337 if (rtype(r
) == RSlot
) {
339 if (s
> sz
* 4095u) {
340 i
= &(Ins
){Oaddr
, Kl
, TMP(IP0
), {r
}};
348 emitins(Ins
*i
, E
*e
)
359 fixarg(&i
->arg
[0], loadsz(i
), e
);
361 fixarg(&i
->arg
[1], storesz(i
), e
);
363 /* most instructions are just pulled out of
364 * the table omap[], some special cases are
367 /* this linear search should really be a binary
369 if (omap
[o
].op
== NOp
)
370 die("no match for %s(%c)",
371 optab
[i
->op
].name
, "wlsd"[i
->cls
]);
372 if (omap
[o
].op
== i
->op
)
373 if (omap
[o
].cls
== i
->cls
|| omap
[o
].cls
== Ka
374 || (omap
[o
].cls
== Ki
&& KBASE(i
->cls
) == 0))
377 emitf(omap
[o
].fmt
, i
, e
);
382 if (req(i
->to
, i
->arg
[0]))
384 if (rtype(i
->to
) == RSlot
) {
386 if (!isreg(i
->arg
[0])) {
391 i
->op
= Ostorew
+ i
->cls
;
397 assert(isreg(i
->to
));
398 switch (rtype(i
->arg
[0])) {
400 c
= &e
->fn
->con
[i
->arg
[0].val
];
401 loadcon(c
, i
->to
.val
, i
->cls
, e
);
408 assert(i
->to
.val
!= R18
);
413 assert(rtype(i
->arg
[0]) == RSlot
);
414 rn
= rname(i
->to
.val
, Kl
);
415 s
= slot(i
->arg
[0], e
);
417 fprintf(e
->f
, "\tadd\t%s, x29, #%"PRIu64
"\n", rn
, s
);
420 "\tmov\t%s, #%"PRIu64
"\n"
421 "\tadd\t%s, x29, %s\n",
426 "\tmov\t%s, #%"PRIu64
"\n"
427 "\tmovk\t%s, #%"PRIu64
", lsl #16\n"
428 "\tadd\t%s, x29, %s\n",
429 rn
, s
& 0xFFFF, rn
, s
>> 16, rn
, rn
433 if (rtype(i
->arg
[0]) != RCon
)
435 c
= &e
->fn
->con
[i
->arg
[0].val
];
437 || c
->sym
.type
!= SGlo
439 die("invalid call argument");
441 p
= l
[0] == '"' ? "" : T
.assym
;
442 fprintf(e
->f
, "\tbl\t%s%s\n", p
, l
);
445 emitf("sub sp, sp, %0", i
, e
);
447 emitf("mov %=, sp", i
, e
);
450 emitdbgloc(i
->arg
[0].val
, i
->arg
[1].val
, e
->f
);
462 for (o
=0, r
=arm64_rclob
; *r
>=0; r
++)
463 o
+= 1 & (e
->fn
->reg
>> *r
);
467 e
->padding
= 4*(f
-e
->fn
->slot
);
468 e
->frame
= 4*f
+ 8*o
;
494 +=============+ <- x29
499 arm64_emitfn(Fn
*fn
, FILE *out
)
501 static char *ctoa
[] = {
502 #define X(c, s) [c] = s,
507 int s
, n
, c
, lbl
, *r
;
513 e
= &(E
){.f
= out
, .fn
= fn
};
515 e
->fn
->lnk
.align
= 4;
516 emitfnlnk(e
->fn
->name
, &e
->fn
->lnk
, e
->f
);
519 if (e
->fn
->vararg
&& !T
.apple
) {
521 fprintf(e
->f
, "\tstr\tq%d, [sp, -16]!\n", n
);
522 for (n
=7; n
>=0; n
-=2)
523 fprintf(e
->f
, "\tstp\tx%d, x%d, [sp, -16]!\n", n
-1, n
);
526 if (e
->frame
+ 16 <= 512)
528 "\tstp\tx29, x30, [sp, -%"PRIu64
"]!\n",
531 else if (e
->frame
<= 4095)
533 "\tsub\tsp, sp, #%"PRIu64
"\n"
534 "\tstp\tx29, x30, [sp, -16]!\n",
537 else if (e
->frame
<= 65535)
539 "\tmov\tx16, #%"PRIu64
"\n"
540 "\tsub\tsp, sp, x16\n"
541 "\tstp\tx29, x30, [sp, -16]!\n",
546 "\tmov\tx16, #%"PRIu64
"\n"
547 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
548 "\tsub\tsp, sp, x16\n"
549 "\tstp\tx29, x30, [sp, -16]!\n",
550 e
->frame
& 0xFFFF, e
->frame
>> 16
552 fputs("\tmov\tx29, sp\n", e
->f
);
553 s
= (e
->frame
- e
->padding
) / 4;
554 for (r
=arm64_rclob
; *r
>=0; r
++)
555 if (e
->fn
->reg
& BIT(*r
)) {
557 i
= &(Ins
){.arg
= {TMP(*r
), SLOT(s
)}};
558 i
->op
= *r
>= V0
? Ostored
: Ostorel
;
562 for (lbl
=0, b
=e
->fn
->start
; b
; b
=b
->link
) {
563 if (lbl
|| b
->npred
> 1)
564 fprintf(e
->f
, "%s%d:\n", T
.asloc
, id0
+b
->id
);
565 for (i
=b
->ins
; i
!=&b
->ins
[b
->nins
]; i
++)
568 switch (b
->jmp
.type
) {
570 fprintf(e
->f
, "\tbrk\t#1000\n");
573 s
= (e
->frame
- e
->padding
) / 4;
574 for (r
=arm64_rclob
; *r
>=0; r
++)
575 if (e
->fn
->reg
& BIT(*r
)) {
577 i
= &(Ins
){Oload
, 0, TMP(*r
), {SLOT(s
)}};
578 i
->cls
= *r
>= V0
? Kd
: Kl
;
582 fputs("\tmov sp, x29\n", e
->f
);
584 if (e
->fn
->vararg
&& !T
.apple
)
588 "\tldp\tx29, x30, [sp], %"PRIu64
"\n",
591 else if (o
- 16 <= 4095)
593 "\tldp\tx29, x30, [sp], 16\n"
594 "\tadd\tsp, sp, #%"PRIu64
"\n",
597 else if (o
- 16 <= 65535)
599 "\tldp\tx29, x30, [sp], 16\n"
600 "\tmov\tx16, #%"PRIu64
"\n"
601 "\tadd\tsp, sp, x16\n",
606 "\tldp\tx29, x30, [sp], 16\n"
607 "\tmov\tx16, #%"PRIu64
"\n"
608 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
609 "\tadd\tsp, sp, x16\n",
610 (o
- 16) & 0xFFFF, (o
- 16) >> 16
612 fprintf(e
->f
, "\tret\n");
616 if (b
->s1
!= b
->link
)
619 T
.asloc
, id0
+b
->s1
->id
625 c
= b
->jmp
.type
- Jjf
;
626 if (c
< 0 || c
> NCmp
)
627 die("unhandled jump %d", b
->jmp
.type
);
628 if (b
->link
== b
->s2
) {
636 ctoa
[c
], T
.asloc
, id0
+b
->s2
->id
643 elf_emitfnfin(fn
->name
, out
);