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 { Odtosi
, Ka
, "fcvtzs %=, %D0" },
93 { Oswtof
, Ka
, "scvtf %=, %W0" },
94 { Osltof
, Ka
, "scvtf %=, %L0" },
95 { Ocall
, Kw
, "blr %L0" },
97 { Oacmp
, Ki
, "cmp %0, %1" },
98 { Oacmn
, Ki
, "cmn %0, %1" },
99 { Oafcmp
, Ka
, "fcmpe %0, %1" },
102 { Oflag+c, Ki, "cset %=, " str },
117 else if (R0
<= r
&& r
<= LR
)
119 default: die("invalid class");
120 case Kw
: sprintf(buf
, "w%d", r
-R0
); break;
122 case Kl
: sprintf(buf
, "x%d", r
-R0
); break;
124 else if (V0
<= r
&& r
<= V30
)
126 default: die("invalid class");
127 case Ks
: sprintf(buf
, "s%d", r
-V0
); break;
129 case Kd
: sprintf(buf
, "d%d", r
-V0
); break;
132 die("invalid register");
139 s
= ((int32_t)s
<< 3) >> 3;
141 return 16 + e
->frame
;
144 return 16 + e
->frame
+ 192 - (s
+2)*8;
146 return 16 + e
->frame
- (s
+2)*8;
148 return 16 + e
->padding
+ 4 * s
;
152 emitf(char *s
, Ins
*i
, E
*e
)
164 while ((c
= *s
++) != '%')
165 if (c
== ' ' && !sp
) {
174 switch ((c
= *s
++)) {
176 die("invalid escape");
191 fputs(rname(R18
, k
), e
->f
);
193 fputs(k
==Ks
? "s31" : "d31", e
->f
);
197 r
= c
== '=' ? i
->to
: i
->arg
[0];
199 fputs(rname(r
.val
, k
), e
->f
);
205 die("invalid second argument");
208 fputs(rname(r
.val
, k
), e
->f
);
211 pc
= &e
->fn
->con
[r
.val
];
213 assert(pc
->type
== CBits
);
215 fprintf(e
->f
, "#%u, lsl #12", n
>>12);
217 fprintf(e
->f
, "#%u", n
);
223 assert(c
== '0' || c
== '1' || c
== '=');
224 r
= c
== '=' ? i
->to
: i
->arg
[c
- '0'];
227 die("todo (arm emit): unhandled ref");
230 fprintf(e
->f
, "[%s]", rname(r
.val
, Kl
));
233 fprintf(e
->f
, "[x29, %"PRIu64
"]", slot(r
.val
, e
));
242 loadcon(Con
*c
, int r
, int k
, FILE *f
)
244 char *rn
, *p
, off
[32];
251 if (c
->type
== CAddr
) {
254 sprintf(off
, "+%"PRIi64
, n
);
257 p
= c
->local
? ".L" : "";
258 fprintf(f
, "\tadrp\t%s, %s%s%s\n",
259 rn
, p
, str(c
->label
), off
);
260 fprintf(f
, "\tadd\t%s, %s, #:lo12:%s%s%s\n",
261 rn
, rn
, p
, str(c
->label
), off
);
264 assert(c
->type
== CBits
);
267 if ((n
| 0xffff) == -1 || arm64_logimm(n
, k
)) {
268 fprintf(f
, "\tmov\t%s, #%"PRIi64
"\n", rn
, n
);
270 fprintf(f
, "\tmov\t%s, #%d\n",
271 rn
, (int)(n
& 0xffff));
272 for (sh
=16; n
>>=16; sh
+=16) {
273 if ((!w
&& sh
== 32) || sh
== 64)
275 fprintf(f
, "\tmovk\t%s, #0x%x, lsl #%d\n",
276 rn
, (unsigned)(n
& 0xffff), sh
);
281 static void emitins(Ins
*, E
*);
284 fixarg(Ref
*pr
, E
*e
)
291 if (rtype(r
) == RSlot
) {
294 i
= &(Ins
){Oaddr
, Kl
, TMP(IP0
), {r
}};
302 emitins(Ins
*i
, E
*e
)
311 fixarg(&i
->arg
[0], e
);
313 fixarg(&i
->arg
[1], e
);
315 /* most instructions are just pulled out of
316 * the table omap[], some special cases are
319 /* this linear search should really be a binary
321 if (omap
[o
].op
== NOp
)
322 die("no match for %s(%c)",
323 optab
[i
->op
].name
, "wlsd"[i
->cls
]);
324 if (omap
[o
].op
== i
->op
)
325 if (omap
[o
].cls
== i
->cls
|| omap
[o
].cls
== Ka
326 || (omap
[o
].cls
== Ki
&& KBASE(i
->cls
) == 0))
329 emitf(omap
[o
].asm, i
, e
);
334 if (req(i
->to
, i
->arg
[0]))
336 if (rtype(i
->to
) == RSlot
) {
337 switch (rtype(i
->arg
[0])) {
339 emitf("ldr %?, %M0\n\tstr %?, %M=", i
, e
);
342 loadcon(&e
->fn
->con
[i
->arg
[0].val
], R18
, i
->cls
, e
->f
);
343 emitf("str %?, %M=", i
, e
);
346 assert(isreg(i
->arg
[0]));
347 emitf("str %0, %M=", i
, e
);
351 assert(isreg(i
->to
));
352 switch (rtype(i
->arg
[0])) {
354 loadcon(&e
->fn
->con
[i
->arg
[0].val
], i
->to
.val
, i
->cls
, e
->f
);
357 emitf("ldr %=, %M0", i
, e
);
364 assert(rtype(i
->arg
[0]) == RSlot
);
365 rn
= rname(i
->to
.val
, Kl
);
366 s
= slot(i
->arg
[0].val
, e
);
368 fprintf(e
->f
, "\tadd\t%s, x29, #%"PRIu64
"\n", rn
, s
);
371 "\tmov\t%s, #%"PRIu64
"\n"
372 "\tadd\t%s, x29, %s\n",
377 "\tmov\t%s, #%"PRIu64
"\n"
378 "\tmovk\t%s, #%"PRIu64
", lsl #16\n"
379 "\tadd\t%s, x29, %s\n",
380 rn
, s
& 0xFFFF, rn
, s
>> 16, rn
, rn
393 for (o
=0, r
=arm64_rclob
; *r
>=0; r
++)
394 o
+= 1 & (e
->fn
->reg
>> *r
);
398 e
->padding
= 4*(f
-e
->fn
->slot
);
399 e
->frame
= 4*f
+ 8*o
;
425 +=============+ <- x29
430 arm64_emitfn(Fn
*fn
, FILE *out
)
432 static char *ctoa
[] = {
433 #define X(c, s) [c] = s,
438 int s
, n
, c
, lbl
, *r
;
444 e
= &(E
){.f
= out
, .fn
= fn
};
447 fprintf(e
->f
, ".text\n");
449 fprintf(e
->f
, ".globl %s\n", e
->fn
->name
);
450 fprintf(e
->f
, "%s:\n", e
->fn
->name
);
454 fprintf(e
->f
, "\tstr\tq%d, [sp, -16]!\n", n
);
455 for (n
=7; n
>=0; n
-=2)
456 fprintf(e
->f
, "\tstp\tx%d, x%d, [sp, -16]!\n", n
-1, n
);
459 if (e
->frame
+ 16 <= 512)
461 "\tstp\tx29, x30, [sp, -%"PRIu64
"]!\n",
464 else if (e
->frame
<= 4095)
466 "\tsub\tsp, sp, #%"PRIu64
"\n"
467 "\tstp\tx29, x30, [sp, -16]!\n",
470 else if (e
->frame
<= 65535)
472 "\tmov\tx16, #%"PRIu64
"\n"
473 "\tsub\tsp, sp, x16\n"
474 "\tstp\tx29, x30, [sp, -16]!\n",
479 "\tmov\tx16, #%"PRIu64
"\n"
480 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
481 "\tsub\tsp, sp, x16\n"
482 "\tstp\tx29, x30, [sp, -16]!\n",
483 e
->frame
& 0xFFFF, e
->frame
>> 16
485 fputs("\tadd\tx29, sp, 0\n", e
->f
);
486 s
= (e
->frame
- e
->padding
) / 4;
487 for (r
=arm64_rclob
; *r
>=0; r
++)
488 if (e
->fn
->reg
& BIT(*r
)) {
490 i
= &(Ins
){.arg
= {TMP(*r
), SLOT(s
)}};
491 i
->op
= *r
>= V0
? Ostored
: Ostorel
;
495 for (lbl
=0, b
=e
->fn
->start
; b
; b
=b
->link
) {
496 if (lbl
|| b
->npred
> 1)
497 fprintf(e
->f
, ".L%d:\n", id0
+b
->id
);
498 for (i
=b
->ins
; i
!=&b
->ins
[b
->nins
]; i
++)
501 switch (b
->jmp
.type
) {
503 s
= (e
->frame
- e
->padding
) / 4;
504 for (r
=arm64_rclob
; *r
>=0; r
++)
505 if (e
->fn
->reg
& BIT(*r
)) {
507 i
= &(Ins
){Oload
, 0, TMP(*r
), {SLOT(s
)}};
508 i
->cls
= *r
>= V0
? Kd
: Kl
;
516 "\tldp\tx29, x30, [sp], %"PRIu64
"\n",
519 else if (o
- 16 <= 4095)
521 "\tldp\tx29, x30, [sp], 16\n"
522 "\tadd\tsp, sp, #%"PRIu64
"\n",
525 else if (o
- 16 <= 65535)
527 "\tldp\tx29, x30, [sp], 16\n"
528 "\tmov\tx16, #%"PRIu64
"\n"
529 "\tadd\tsp, sp, x16\n",
534 "\tldp\tx29, x30, [sp], 16\n"
535 "\tmov\tx16, #%"PRIu64
"\n"
536 "\tmovk\tx16, #%"PRIu64
", lsl #16\n"
537 "\tadd\tsp, sp, x16\n",
538 (o
- 16) & 0xFFFF, (o
- 16) >> 16
540 fprintf(e
->f
, "\tret\n");
544 if (b
->s1
!= b
->link
)
545 fprintf(e
->f
, "\tb\t.L%d\n", id0
+b
->s1
->id
);
550 c
= b
->jmp
.type
- Jjf
;
551 if (c
< 0 || c
> NCmp
)
552 die("unhandled jump %d", b
->jmp
.type
);
553 if (b
->link
== b
->s2
) {
559 fprintf(e
->f
, "\tb%s\t.L%d\n", ctoa
[c
], id0
+b
->s2
->id
);