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 { Oand
, Ki
, "and %=, %0, %1" },
47 { Oor
, Ki
, "orr %=, %0, %1" },
48 { Oxor
, Ki
, "eor %=, %0, %1" },
49 { Osar
, Ki
, "asr %=, %0, %1" },
50 { Oshr
, Ki
, "lsr %=, %0, %1" },
51 { Oshl
, Ki
, "lsl %=, %0, %1" },
52 { Omul
, Ki
, "mul %=, %0, %1" },
53 { Omul
, Ka
, "fmul %=, %0, %1" },
54 { Odiv
, Ki
, "sdiv %=, %0, %1" },
55 { Odiv
, Ka
, "fdiv %=, %0, %1" },
56 { Oudiv
, Ki
, "udiv %=, %0, %1" },
57 { Orem
, Ki
, "sdiv %?, %0, %1\n\tmsub\t%=, %?, %1, %0" },
58 { Ourem
, Ki
, "udiv %?, %0, %1\n\tmsub\t%=, %?, %1, %0" },
59 { Ocopy
, Ki
, "mov %=, %0" },
60 { Ocopy
, Ka
, "fmov %=, %0" },
61 { Oswap
, Ki
, "mov %?, %0\n\tmov\t%0, %1\n\tmov\t%1, %?" },
62 { Oswap
, Ka
, "fmov %?, %0\n\tfmov\t%0, %1\n\tfmov\t%1, %?" },
63 { Ostoreb
, Kw
, "strb %W0, %M1" },
64 { Ostoreh
, Kw
, "strh %W0, %M1" },
65 { Ostorew
, Kw
, "str %W0, %M1" },
66 { Ostorel
, Kw
, "str %L0, %M1" },
67 { Ostores
, Kw
, "str %S0, %M1" },
68 { Ostored
, Kw
, "str %D0, %M1" },
69 { Oloadsb
, Ki
, "ldrsb %=, %M0" },
70 { Oloadub
, Ki
, "ldrb %W=, %M0" },
71 { Oloadsh
, Ki
, "ldrsh %=, %M0" },
72 { Oloaduh
, Ki
, "ldrh %W=, %M0" },
73 { Oloadsw
, Kw
, "ldr %=, %M0" },
74 { Oloadsw
, Kl
, "ldrsw %=, %M0" },
75 { Oloaduw
, Ki
, "ldr %W=, %M0" },
76 { Oload
, Ka
, "ldr %=, %M0" },
77 { Oextsb
, Ki
, "sxtb %=, %W0" },
78 { Oextub
, Ki
, "uxtb %W=, %W0" },
79 { Oextsh
, Ki
, "sxth %=, %W0" },
80 { Oextuh
, Ki
, "uxth %W=, %W0" },
81 { Oextsw
, Ki
, "sxtw %L=, %W0" },
82 { Oextuw
, Ki
, "mov %W=, %W0" },
83 { Oexts
, Kd
, "fcvt %=, %S0" },
84 { Otruncd
, Ks
, "fcvt %=, %D0" },
85 { Ocast
, Kw
, "fmov %=, %S0" },
86 { Ocast
, Kl
, "fmov %=, %D0" },
87 { Ocast
, Ks
, "fmov %=, %W0" },
88 { Ocast
, Kd
, "fmov %=, %L0" },
89 { Ostosi
, Ka
, "fcvtzs %=, %S0" },
90 { Odtosi
, Ka
, "fcvtzs %=, %D0" },
91 { Oswtof
, Ka
, "scvtf %=, %W0" },
92 { Osltof
, Ka
, "scvtf %=, %L0" },
93 { Ocall
, Kw
, "blr %L0" },
95 { Oacmp
, Ki
, "cmp %0, %1" },
96 { Oacmn
, Ki
, "cmn %0, %1" },
97 { Oafcmp
, Ka
, "fcmpe %0, %1" },
100 { Oflag+c, Ki, "cset %=, " str },
115 else if (R0
<= r
&& r
<= LR
)
117 default: die("invalid class");
118 case Kw
: sprintf(buf
, "w%d", r
-R0
); break;
120 case Kl
: sprintf(buf
, "x%d", r
-R0
); break;
122 else if (V0
<= r
&& r
<= V30
)
124 default: die("invalid class");
125 case Ks
: sprintf(buf
, "s%d", r
-V0
); break;
127 case Kd
: sprintf(buf
, "d%d", r
-V0
); break;
130 die("invalid register");
137 s
= ((int32_t)s
<< 3) >> 3;
139 return 16 + e
->frame
;
142 return 16 + e
->frame
+ 192 - (s
+2)*8;
144 return 16 + e
->frame
- (s
+2)*8;
146 return 16 + e
->padding
+ 4 * s
;
150 emitf(char *s
, Ins
*i
, E
*e
)
162 while ((c
= *s
++) != '%')
163 if (c
== ' ' && !sp
) {
172 switch ((c
= *s
++)) {
174 die("invalid escape");
189 fputs(rname(R18
, k
), e
->f
);
191 fputs(k
==Ks
? "s31" : "d31", e
->f
);
195 r
= c
== '=' ? i
->to
: i
->arg
[0];
197 fputs(rname(r
.val
, k
), e
->f
);
203 die("invalid second argument");
206 fputs(rname(r
.val
, k
), e
->f
);
209 pc
= &e
->fn
->con
[r
.val
];
211 assert(pc
->type
== CBits
);
213 fprintf(e
->f
, "#%u, lsl #12", n
>>12);
215 fprintf(e
->f
, "#%u", n
);
221 assert(c
== '0' || c
== '1');
223 assert(isreg(r
) && "TODO emit non reg addresses");
224 fprintf(e
->f
, "[%s]", rname(r
.val
, Kl
));
231 loadcon(Con
*c
, int r
, int k
, FILE *f
)
233 char *rn
, *p
, off
[32];
240 if (c
->type
== CAddr
) {
243 sprintf(off
, "+%"PRIi64
, n
);
246 p
= c
->local
? ".L" : "";
247 fprintf(f
, "\tadrp\t%s, %s%s%s\n",
248 rn
, p
, str(c
->label
), off
);
249 fprintf(f
, "\tadd\t%s, %s, #:lo12:%s%s%s\n",
250 rn
, rn
, p
, str(c
->label
), off
);
253 assert(c
->type
== CBits
);
256 if ((n
| 0xffff) == -1 || arm64_logimm(n
, k
)) {
257 fprintf(f
, "\tmov\t%s, #%"PRIi64
"\n", rn
, n
);
259 fprintf(f
, "\tmov\t%s, #%d\n",
260 rn
, (int)(n
& 0xffff));
261 for (sh
=16; n
>>=16; sh
+=16) {
262 if ((!w
&& sh
== 32) || sh
== 64)
264 fprintf(f
, "\tmovk\t%s, #0x%x, lsl #%d\n",
265 rn
, (unsigned)(n
& 0xffff), sh
);
271 emitins(Ins
*i
, E
*e
)
280 /* most instructions are just pulled out of
281 * the table omap[], some special cases are
284 /* this linear search should really be a binary
286 if (omap
[o
].op
== NOp
)
287 die("no match for %s(%c)",
288 optab
[i
->op
].name
, "wlsd"[i
->cls
]);
289 if (omap
[o
].op
== i
->op
)
290 if (omap
[o
].cls
== i
->cls
|| omap
[o
].cls
== Ka
291 || (omap
[o
].cls
== Ki
&& KBASE(i
->cls
) == 0))
294 emitf(omap
[o
].asm, i
, e
);
299 if (req(i
->to
, i
->arg
[0]))
301 if (rtype(i
->arg
[0]) != RCon
)
303 loadcon(&e
->fn
->con
[i
->arg
[0].val
], i
->to
.val
, i
->cls
, e
->f
);
306 assert(rtype(i
->arg
[0]) == RSlot
);
307 rn
= rname(i
->to
.val
, Kl
);
308 s
= slot(i
->arg
[0].val
, e
);
310 fprintf(e
->f
, "\tadd\t%s, x29, #%"PRIu64
"\n", rn
, s
);
313 "\tmov\t%s, #%"PRIu64
"\n"
314 "\tadd\t%s, x29, %s\n",
329 for (o
=0, r
=arm64_rclob
; *r
>=0; r
++)
330 o
+= 1 & (e
->fn
->reg
>> *r
);
334 e
->padding
= 4*(f
-e
->fn
->slot
);
335 e
->frame
= 4*f
+ 8*o
;
361 +=============+ <- x29
366 arm64_emitfn(Fn
*fn
, FILE *out
)
368 static char *ctoa
[] = {
369 #define X(c, s) [c] = s,
380 e
= &(E
){.f
= out
, .fn
= fn
};
383 fprintf(e
->f
, ".text\n");
385 fprintf(e
->f
, ".globl %s\n", e
->fn
->name
);
386 fprintf(e
->f
, "%s:\n", e
->fn
->name
);
390 fprintf(e
->f
, "\tstr\tq%d, [sp, -16]!\n", n
);
391 for (n
=7; n
>=0; n
-=2)
392 fprintf(e
->f
, "\tstp\tx%d, x%d, [sp, -16]!\n", n
-1, n
);
395 if (e
->frame
+ 16 <= 512)
397 "\tstp\tx29, x30, [sp, -%"PRIu64
"]!\n",
400 else if (e
->frame
<= 4095)
402 "\tsub\tsp, sp, #%"PRIu64
"\n"
403 "\tstp\tx29, x30, [sp, -16]!\n",
408 "\tmov\tx16, #%"PRIu64
"\n"
409 "\tsub\tsp, sp, x16\n"
410 "\tstp\tx29, x30, [sp, -16]!\n",
413 fputs("\tadd\tx29, sp, 0\n", e
->f
);
414 for (o
=e
->frame
+16, r
=arm64_rclob
; *r
>=0; r
++)
415 if (e
->fn
->reg
& BIT(*r
))
417 "\tstr\t%s, [sp, %"PRIu64
"]\n",
418 rname(*r
, Kx
), o
-= 8
421 for (lbl
=0, b
=e
->fn
->start
; b
; b
=b
->link
) {
422 if (lbl
|| b
->npred
> 1)
423 fprintf(e
->f
, ".L%d:\n", id0
+b
->id
);
424 for (i
=b
->ins
; i
!=&b
->ins
[b
->nins
]; i
++)
427 switch (b
->jmp
.type
) {
429 for (o
=e
->frame
+16, r
=arm64_rclob
; *r
>=0; r
++)
430 if (e
->fn
->reg
& BIT(*r
))
432 "\tldr\t%s, [sp, %"PRIu64
"]\n",
433 rname(*r
, Kx
), o
-= 8
440 "\tldp\tx29, x30, [sp], %"PRIu64
"\n",
443 else if (o
- 16 <= 4095)
445 "\tldp\tx29, x30, [sp], 16\n"
446 "\tadd\tsp, sp, #%"PRIu64
"\n",
451 "\tldp\tx29, x30, [sp], 16\n"
452 "\tmov\tx16, #%"PRIu64
"\n"
453 "\tadd\tsp, sp, x16\n",
456 fprintf(e
->f
, "\tret\n");
460 if (b
->s1
!= b
->link
)
461 fprintf(e
->f
, "\tb\t.L%d\n", id0
+b
->s1
->id
);
466 c
= b
->jmp
.type
- Jjf
;
467 if (c
< 0 || c
> NCmp
)
468 die("unhandled jump %d", b
->jmp
.type
);
469 if (b
->link
== b
->s2
) {
475 fprintf(e
->f
, "\tb%s\t.L%d\n", ctoa
[c
], id0
+b
->s2
->id
);