History

arm64-win32 support : arm64 assembler

Benjamin Oldenburg committed 7 months ago

Commit f459aff1 parent ea823185 files · +3070 −29Browse files

Unified · Split

5 files
  1. arm64-asm.c +2208 −22
  2. arm64-tok.h +840 −0
  3. tccasm.c +14 −3
  4. tccpp.c +3 −3
  5. tcctok.h +5 −1
arm64-asm.c+2208−22
@@ -1,13 +1,17 @@
1/*************************************************************/1/*************************************************************/
2/*2/*
3 * ARM64 dummy assembler for TCC3 * ARM64 (AArch64) assembler for TCC
4 *4 *
5 * Based on ARM64 Architecture Reference Manual
6 * Supports AArch64 assembler parsing and extended inline asm
7 * with operands, constraints, and clobbers.
5 */8 */
6 9
7#ifdef TARGET_DEFS_ONLY10#ifdef TARGET_DEFS_ONLY
8 11
9#define CONFIG_TCC_ASM12#define CONFIG_TCC_ASM
10#define NB_ASM_REGS 1613/* 32 general purpose + 32 SIMD/FP registers */
14#define NB_ASM_REGS 64
11 15
12ST_FUNC void g(int c);16ST_FUNC void g(int c);
13ST_FUNC void gen_le16(int c);17ST_FUNC void gen_le16(int c);
@@ -16,13 +20,98 @@ ST_FUNC void gen_le32(int c); · 2 unmodified lines
16/*************************************************************/20/*************************************************************/
17#else21#else
18/*************************************************************/22/*************************************************************/
23
19#define USING_GLOBALS24#define USING_GLOBALS
20#include "tcc.h"25#include "tcc.h"
21 26
22static void asm_error(void)27/* Register type flags */
23{28#define REG_X 0x01 /* 64-bit general purpose */
24 tcc_error("ARM asm not implemented.");29#define REG_W 0x02 /* 32-bit general purpose */
25}30#define REG_V 0x04 /* 128-bit SIMD */
31#define REG_D 0x08 /* 64-bit FP */
32#define REG_S 0x10 /* 32-bit FP */
33#define REG_H 0x20 /* 16-bit FP */
34#define REG_B 0x40 /* 8-bit SIMD */
35
36/* Operand types */
37enum {
38 OPT_REG,
39 OPT_IM,
40 OPT_ADDR,
41 OPT_COND,
42};
43
44#define OP_REG (1 << OPT_REG)
45#define OP_IM (1 << OPT_IM)
46#define OP_ADDR (1 << OPT_ADDR)
47#define OP_COND (1 << OPT_COND)
48
49/* Register allocation masks */
50#define REG_OUT_MASK 0x01
51#define REG_IN_MASK 0x02
52
53#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
54
55/* ARM64 register constants */
56#define TREG_X0 0
57#define TREG_X1 1
58#define TREG_X2 2
59#define TREG_X3 3
60#define TREG_X4 4
61#define TREG_X5 5
62#define TREG_X6 6
63#define TREG_X7 7
64#define TREG_X8 8
65#define TREG_X9 9
66#define TREG_X10 10
67#define TREG_X11 11
68#define TREG_X12 12
69#define TREG_X13 13
70#define TREG_X14 14
71#define TREG_X15 15
72#define TREG_X16 16
73#define TREG_X17 17
74#define TREG_X18 18
75#define TREG_X19 19
76#define TREG_X20 20
77#define TREG_X21 21
78#define TREG_X22 22
79#define TREG_X23 23
80#define TREG_X24 24
81#define TREG_X25 25
82#define TREG_X26 26
83#define TREG_X27 27
84#define TREG_X28 28
85#define TREG_X29 29
86#define TREG_X30 30
87#define TREG_SP 31
88
89#ifdef TCC_TARGET_PE
90#define ARM64_FREG_BASE 19
91#else
92#define ARM64_FREG_BASE 20
93#endif
94#define ARM64_FREG_LAST (ARM64_FREG_BASE + 7)
95
96typedef struct Operand {
97 uint32_t type;
98 int8_t reg;
99 int8_t reg2;
100 uint8_t reg_type;
101 uint8_t shift;
102 uint8_t addr_mode;
103 int reg_tok;
104 ExprValue e;
105} Operand;
106
107enum {
108 ADDR_OFF,
109 ADDR_PRE,
110 ADDR_POST,
111};
112
113/* Forward declaration */
114static void parse_addr_operand(TCCState *s1, Operand *op);
26 115
27/* XXX: make it faster ? */116/* XXX: make it faster ? */
28ST_FUNC void g(int c)117ST_FUNC void g(int c)
@@ -37,16 +126,16 @@ ST_FUNC void g(int c) · 8 unmodified lines
37 ind = ind1;126 ind = ind1;
38}127}
39 128
40ST_FUNC void gen_le16 (int i)129ST_FUNC void gen_le16(int c)
41{130{
42 g(i);131 g(c);
43 g(i>>8);132 g(c >> 8);
44}133}
45 134
46ST_FUNC void gen_le32 (int i)135ST_FUNC void gen_le32(int c)
47{136{
48 gen_le16(i);137 gen_le16(c);
49 gen_le16(i>>16);138 gen_le16(c >> 16);
50}139}
51 140
52ST_FUNC void gen_expr32(ExprValue *pe)141ST_FUNC void gen_expr32(ExprValue *pe)
@@ -54,22 +143,1889 @@ ST_FUNC void gen_expr32(ExprValue *pe) · 1 unmodified line
54 gen_le32(pe->v);143 gen_le32(pe->v);
55}144}
56 145
146/* Emit 32-bit instruction */
147static void emit_instr32(uint32_t val)
148{
149 if (nocode_wanted)
150 return;
151 if (ind + 4 > cur_text_section->data_allocated)
152 section_realloc(cur_text_section, ind + 4);
153 write32le(cur_text_section->data + ind, val);
154 ind += 4;
155}
156
157/* Parse ARM64 register token for assembler syntax. */
158static int arm64_parse_asm_reg(int t)
159{
160 /* X registers (64-bit) */
161 if (t >= TOK_ASM_x0 && t <= TOK_ASM_x30)
162 return t - TOK_ASM_x0;
163 /* W registers (32-bit) */
164 if (t >= TOK_ASM_w0 && t <= TOK_ASM_w30)
165 return t - TOK_ASM_w0;
166 /* V registers (128-bit SIMD) */
167 if (t >= TOK_ASM_v0 && t <= TOK_ASM_v31)
168 return (t - TOK_ASM_v0) + 32;
169 /* D registers (64-bit FP) */
170 if (t >= TOK_ASM_d0 && t <= TOK_ASM_d31)
171 return (t - TOK_ASM_d0) + 32;
172 /* S registers (32-bit FP) */
173 if (t >= TOK_ASM_s0 && t <= TOK_ASM_s31)
174 return (t - TOK_ASM_s0) + 32;
175 /* H registers (16-bit FP) */
176 if (t >= TOK_ASM_h0 && t <= TOK_ASM_h31)
177 return (t - TOK_ASM_h0) + 32;
178 /* B registers (8-bit SIMD) */
179 if (t >= TOK_ASM_b0 && t <= TOK_ASM_b31)
180 return (t - TOK_ASM_b0) + 32;
181 /* Special registers */
182 if (t == TOK_ASM_sp || t == TOK_ASM_xzr || t == TOK_ASM_wzr)
183 return 31; /* SP/ZR encoded as 31 */
184 return -1;
185}
186
187/* Get register type from token */
188static uint8_t get_reg_type(int t)
189{
190 if (t >= TOK_ASM_x0 && t <= TOK_ASM_x30)
191 return REG_X;
192 if (t >= TOK_ASM_w0 && t <= TOK_ASM_w30)
193 return REG_W;
194 if (t >= TOK_ASM_v0 && t <= TOK_ASM_v31)
195 return REG_V;
196 if (t >= TOK_ASM_d0 && t <= TOK_ASM_d31)
197 return REG_D;
198 if (t >= TOK_ASM_s0 && t <= TOK_ASM_s31)
199 return REG_S;
200 if (t >= TOK_ASM_h0 && t <= TOK_ASM_h31)
201 return REG_H;
202 if (t >= TOK_ASM_b0 && t <= TOK_ASM_b31)
203 return REG_B;
204 /* Special registers - sp is 64-bit, xzr is 64-bit, wzr is 32-bit */
205 if (t == TOK_ASM_sp || t == TOK_ASM_xzr)
206 return REG_X;
207 if (t == TOK_ASM_wzr)
208 return REG_W;
209 return REG_X;
210}
211
212/* Parse condition code */
213static int parse_condition(int t)
214{
215 switch (t) {
216 case TOK_ASM_eq: return 0;
217 case TOK_ASM_ne: return 1;
218 case TOK_ASM_cs:
219 case TOK_ASM_hs: return 2;
220 case TOK_ASM_cc:
221 case TOK_ASM_lo: return 3;
222 case TOK_ASM_mi: return 4;
223 case TOK_ASM_pl: return 5;
224 case TOK_ASM_vs: return 6;
225 case TOK_ASM_vc: return 7;
226 case TOK_ASM_hi: return 8;
227 case TOK_ASM_ls: return 9;
228 case TOK_ASM_ge: return 10;
229 case TOK_ASM_lt: return 11;
230 case TOK_ASM_gt: return 12;
231 case TOK_ASM_le: return 13;
232 case TOK_ASM_al: return 14;
233 default: return -1;
234 }
235}
236
237static int parse_barrier_option_name(int t)
238{
239 const char *name;
240
241 if (t < TOK_IDENT)
242 return -1;
243 name = get_tok_str(t, NULL);
244 if (!strcmp(name, "oshld")) return 0x1;
245 if (!strcmp(name, "oshst")) return 0x2;
246 if (!strcmp(name, "osh")) return 0x3;
247 if (!strcmp(name, "nshld")) return 0x5;
248 if (!strcmp(name, "nshst")) return 0x6;
249 if (!strcmp(name, "nsh")) return 0x7;
250 if (!strcmp(name, "ishld")) return 0x9;
251 if (!strcmp(name, "ishst")) return 0xA;
252 if (!strcmp(name, "ish")) return 0xB;
253 if (!strcmp(name, "ld")) return 0xD;
254 if (!strcmp(name, "st")) return 0xE;
255 if (!strcmp(name, "sy")) return 0xF;
256 return -1;
257}
258
259static int arm64_parse_regvar(int t)
260{
261 if (t >= TOK_ASM_x0 && t <= TOK_ASM_x30)
262 return t - TOK_ASM_x0;
263 if (t >= TOK_ASM_v0 && t <= TOK_ASM_v7)
264 return ARM64_FREG_BASE + (t - TOK_ASM_v0);
265 if (t >= TOK_ASM_d0 && t <= TOK_ASM_d7)
266 return ARM64_FREG_BASE + (t - TOK_ASM_d0);
267 if (t >= TOK_ASM_s0 && t <= TOK_ASM_s7)
268 return ARM64_FREG_BASE + (t - TOK_ASM_s0);
269 if (t >= TOK_ASM_h0 && t <= TOK_ASM_h7)
270 return ARM64_FREG_BASE + (t - TOK_ASM_h0);
271 if (t >= TOK_ASM_b0 && t <= TOK_ASM_b7)
272 return ARM64_FREG_BASE + (t - TOK_ASM_b0);
273 return -1;
274}
275
276/* Parse a single operand */
277static void parse_operand(TCCState *s1, Operand *op)
278{
279 int reg;
280
281 op->type = 0;
282 op->reg = -1;
283 op->reg2 = -1;
284 op->reg_type = 0;
285 op->shift = 0;
286 op->addr_mode = ADDR_OFF;
287 op->reg_tok = 0;
288
289 /* Address operand in brackets [xn, ...] */
290 if (tok == '[') {
291 parse_addr_operand(s1, op);
292 return;
293 }
294
295 /* Register */
296 reg = arm64_parse_asm_reg(tok);
297 if (reg >= 0) {
298 op->type = OP_REG;
299 op->reg = reg;
300 op->reg_type = get_reg_type(tok);
301 op->reg_tok = tok;
302 next();
303 return;
304 }
305
306 /* Condition code */
307 reg = parse_condition(tok);
308 if (reg >= 0) {
309 op->type = OP_COND;
310 op->reg = reg;
311 next();
312 return;
313 }
314
315 /* Immediate or address expression */
316 if (tok == '#' || tok == ':' || tok == '@' || tok == '$') {
317 next();
318 asm_expr(s1, &op->e);
319 op->type = OP_IM;
320 } else if (tok >= TOK_IDENT) {
321 tcc_error("invalid operand '%s'", get_tok_str(tok, &tokc));
322 op->type = OP_IM;
323 } else {
324 asm_expr(s1, &op->e);
325 op->type = OP_IM;
326 }
327}
328
329/* Parse a symbolic/immediate expression operand used by branch instructions. */
330static void parse_expr_operand(TCCState *s1, Operand *op)
331{
332 op->type = OP_IM;
333 op->reg = -1;
334 op->reg2 = -1;
335 op->reg_type = 0;
336 op->shift = 0;
337 op->addr_mode = ADDR_OFF;
338 op->reg_tok = 0;
339
340 if (tok == '#' || tok == ':' || tok == '@' || tok == '$')
341 next();
342 asm_expr(s1, &op->e);
343}
344
345/* Parse address operand in brackets [xn, ...] */
346static void parse_addr_operand(TCCState *s1, Operand *op)
347{
348 int reg;
349
350 op->type = OP_ADDR;
351 op->reg = -1;
352 op->reg2 = -1;
353 op->e.v = 0;
354 op->e.sym = NULL;
355 op->addr_mode = ADDR_OFF;
356 op->reg_tok = 0;
357
358 skip('[');
359 reg = arm64_parse_asm_reg(tok);
360 if (reg < 0 || reg >= 32) {
361 tcc_error("invalid register in address operand");
362 return;
363 }
364 op->reg = reg;
365 op->reg_tok = tok;
366 next();
367 /* Check for offset */
368 if (tok == ',') {
369 next();
370 if (tok == '#' || tok == '@' || tok == '$')
371 next();
372 asm_expr(s1, &op->e);
373 }
374 skip(']');
375 if (tok == '!') {
376 op->addr_mode = ADDR_PRE;
377 next();
378 } else if (tok == ',') {
379 op->addr_mode = ADDR_POST;
380 next();
381 if (tok == '#' || tok == '@' || tok == '$')
382 next();
383 asm_expr(s1, &op->e);
384 }
385}
386
387/* Generate MOVZ/MOVN/MOVK with base opcode */
388static void gen_mov_with_base(int rd, uint16_t imm, int shift,
389 int is_64bit, uint32_t base_opcode)
390{
391 uint32_t instr = base_opcode;
392 if (is_64bit) instr |= ARM64_SF(1);
393 /* shift is halfword index (0-3), encode as LSL #0/16/32/48 */
394 instr |= ARM64_IMM_HW(imm, shift);
395 instr |= ARM64_RD(rd);
396 emit_instr32(instr);
397}
398
399static void gen_movz(int rd, uint16_t imm, int shift, int is_64bit)
400{
401 gen_mov_with_base(rd, imm, shift, is_64bit, ARM64_MOVZ);
402}
403
404/* Generate MOVN instruction */
405static void gen_movn(int rd, uint16_t imm, int shift, int is_64bit)
406{
407 gen_mov_with_base(rd, imm, shift, is_64bit, ARM64_MOVN);
408}
409
410/* Generate MOVK instruction */
411static void gen_movk(int rd, uint16_t imm, int shift, int is_64bit)
412{
413 gen_mov_with_base(rd, imm, shift, is_64bit, ARM64_MOVK);
414}
415
416/* Generate ADD (immediate) */
417static void gen_add_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags)
418{
419 uint32_t instr = ARM64_ADD_IMM;
420 uint32_t imm12;
421
422 if (is_64bit) instr |= ARM64_SF(1);
423 if (setflags) instr |= ARM64_S(1);
424
425 if (imm <= 0xFFF) {
426 imm12 = imm;
427 } else if (!(imm & 0xFFF) && (imm >> 12) <= 0xFFF) {
428 instr |= ARM64_SH(1);
429 imm12 = imm >> 12;
430 } else {
431 tcc_error("add immediate out of range");
432 return;
433 }
434
435 instr |= ARM64_IMM12(imm12);
436 instr |= ARM64_RN(rn);
437 instr |= ARM64_RD(rd);
438 emit_instr32(instr);
439}
440
441/* Generate SUB (immediate) */
442static void gen_sub_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags)
443{
444 uint32_t instr = ARM64_SUB_IMM;
445 uint32_t imm12;
446
447 if (is_64bit) instr |= ARM64_SF(1);
448 if (setflags) instr |= ARM64_S(1);
449
450 if (imm <= 0xFFF) {
451 imm12 = imm;
452 } else if (!(imm & 0xFFF) && (imm >> 12) <= 0xFFF) {
453 instr |= ARM64_SH(1);
454 imm12 = imm >> 12;
455 } else {
456 tcc_error("sub immediate out of range");
457 return;
458 }
459
460 instr |= ARM64_IMM12(imm12);
461 instr |= ARM64_RN(rn);
462 instr |= ARM64_RD(rd);
463 emit_instr32(instr);
464}
465
466/* Generate data processing register instruction */
467static void gen_dp_reg(uint32_t opcode, int rd, int rn, int rm, int is_64bit)
468{
469 uint32_t instr = opcode;
470 if (is_64bit) instr |= ARM64_SF(1);
471 instr |= ARM64_RM(rm);
472 instr |= ARM64_RN(rn);
473 instr |= ARM64_RD(rd);
474 emit_instr32(instr);
475}
476
477/* Generate LDR/STR (unsigned immediate) */
478static void gen_ldst_imm(uint32_t base_opcode, int rt, int rn,
479 int32_t offset, int size_log2)
480{
481 uint32_t instr = base_opcode;
482 uint32_t unscaled_opcode = 0;
483 uint32_t imm12;
484
485 if (offset >= 0 && !(offset & ((1 << size_log2) - 1))) {
486 imm12 = offset >> size_log2;
487 if (imm12 <= 0xFFF) {
488 instr |= ARM64_IMM12(imm12);
489 instr |= ARM64_RN(rn);
490 instr |= ARM64_RT(rt);
491 emit_instr32(instr);
492 return;
493 }
494 }
495
496 switch (base_opcode) {
497 case ARM64_LDR_X: unscaled_opcode = ARM64_LDUR_X; break;
498 case ARM64_LDR_W: unscaled_opcode = ARM64_LDUR_W; break;
499 case ARM64_LDR_B: unscaled_opcode = ARM64_LDUR_B; break;
500 case ARM64_LDR_H: unscaled_opcode = ARM64_LDUR_H; break;
501 case ARM64_LDR_D: unscaled_opcode = ARM64_LDUR_D_SIMD; break;
502 case ARM64_STR_X: unscaled_opcode = ARM64_STUR_X; break;
503 case ARM64_STR_W: unscaled_opcode = ARM64_STUR_W; break;
504 case ARM64_STR_B: unscaled_opcode = ARM64_STUR_B; break;
505 case ARM64_STR_H: unscaled_opcode = ARM64_STUR_H; break;
506 case ARM64_STR_D: unscaled_opcode = ARM64_STUR_D_SIMD; break;
507 }
508
509 if (unscaled_opcode && offset >= -256 && offset <= 255) {
510 instr = unscaled_opcode;
511 instr |= ((uint32_t)offset & 0x1FFU) << 12;
512 instr |= ARM64_RN(rn);
513 instr |= ARM64_RT(rt);
514 emit_instr32(instr);
515 return;
516 }
517
518 if (offset & ((1 << size_log2) - 1))
519 tcc_error("invalid load/store offset");
520 tcc_error("load/store offset out of range");
521}
522
523/* Generate STP/LDP (signed immediate) */
524static void gen_ldst_pair(uint32_t base_opcode, int rt, int rt2, int rn,
525 int32_t offset, int size_log2)
526{
527 int32_t imm7;
528 uint32_t instr = base_opcode;
529
530 if (offset & ((1 << size_log2) - 1))
531 tcc_error("invalid pair load/store offset");
532 imm7 = offset >> size_log2;
533 if (imm7 < -64 || imm7 > 63)
534 tcc_error("pair load/store offset out of range");
535
536 instr |= ARM64_IMM7(imm7);
537 instr |= ARM64_RT2(rt2);
538 instr |= ARM64_RN(rn);
539 instr |= ARM64_RT(rt);
540 emit_instr32(instr);
541}
542
543/* Generate B (branch) */
544/* Generate B/BL with base opcode */
545static void gen_b_or_bl(int32_t offset, uint32_t base_opcode)
546{
547 uint32_t instr = base_opcode;
548 instr |= ARM64_OFFSET26(offset);
549 emit_instr32(instr);
550}
551
552static void gen_b(int32_t offset)
553{
554 gen_b_or_bl(offset, ARM64_B);
555}
556
557/* Generate BL (branch with link) */
558static void gen_bl(int32_t offset)
559{
560 gen_b_or_bl(offset, ARM64_BL);
561}
562
563/* Generate BR (branch to register) */
564static void gen_br(int rn)
565{
566 uint32_t instr = ARM64_BR;
567 instr |= ARM64_RN(rn);
568 emit_instr32(instr);
569}
570
571/* Generate BLR (branch with link to register) */
572static void gen_blr(int rn)
573{
574 uint32_t instr = ARM64_BLR;
575 instr |= ARM64_RN(rn);
576 emit_instr32(instr);
577}
578
579/* Generate RET */
580static void gen_ret(int rn)
581{
582 uint32_t instr = ARM64_RET;
583 instr |= ARM64_RN(rn);
584 emit_instr32(instr);
585}
586
587/* Generate conditional branch */
588static void gen_b_cond(int cond, int32_t offset)
589{
590 uint32_t instr = ARM64_B_COND;
591 instr |= ARM64_OFFSET19(offset);
592 instr |= ARM64_COND(cond);
593 emit_instr32(instr);
594}
595
596/* Generate CBZ */
597/* Generate CBZ/CBNZ with base opcode */
598static void gen_cbz_or_cbnz(int rt, int32_t offset, int is_64bit, uint32_t base_opcode)
599{
600 uint32_t instr = base_opcode;
601 if (is_64bit) instr |= ARM64_SF(1);
602 instr |= ARM64_OFFSET19(offset);
603 instr |= ARM64_RT(rt);
604 emit_instr32(instr);
605}
606
607static void gen_cbz(int rt, int32_t offset, int is_64bit)
608{
609 gen_cbz_or_cbnz(rt, offset, is_64bit, ARM64_CBZ);
610}
611
612/* Generate CBNZ */
613static void gen_cbnz(int rt, int32_t offset, int is_64bit)
614{
615 gen_cbz_or_cbnz(rt, offset, is_64bit, ARM64_CBNZ);
616}
617
618/* Generate MOV (register) - ORR with zero register */
619static void gen_mov_reg(int rd, int rm, int is_64bit)
620{
621 uint32_t instr = ARM64_MOV_REG;
622 if (is_64bit) instr |= ARM64_SF(1);
623 instr |= ARM64_RM(rm);
624 instr |= ARM64_RD(rd);
625 emit_instr32(instr);
626}
627
628static int arm64_asm_encode_bimm64(uint64_t x)
629{
630 int neg, rep, pos, len;
631
632 neg = x & 1;
633 if (neg)
634 x = ~x;
635 if (!x)
636 return -1;
637
638 if (x >> 2 == (x & ((((uint64_t)1) << (64 - 2)) - 1)))
639 rep = 2, x &= (((uint64_t)1) << 2) - 1;
640 else if (x >> 4 == (x & ((((uint64_t)1) << (64 - 4)) - 1)))
641 rep = 4, x &= (((uint64_t)1) << 4) - 1;
642 else if (x >> 8 == (x & ((((uint64_t)1) << (64 - 8)) - 1)))
643 rep = 8, x &= (((uint64_t)1) << 8) - 1;
644 else if (x >> 16 == (x & ((((uint64_t)1) << (64 - 16)) - 1)))
645 rep = 16, x &= (((uint64_t)1) << 16) - 1;
646 else if (x >> 32 == (x & ((((uint64_t)1) << (64 - 32)) - 1)))
647 rep = 32, x &= (((uint64_t)1) << 32) - 1;
648 else
649 rep = 64;
650
651 pos = 0;
652 if (!(x & ((((uint64_t)1) << 32) - 1)))
653 x >>= 32, pos += 32;
654 if (!(x & ((((uint64_t)1) << 16) - 1)))
655 x >>= 16, pos += 16;
656 if (!(x & ((((uint64_t)1) << 8) - 1)))
657 x >>= 8, pos += 8;
658 if (!(x & ((((uint64_t)1) << 4) - 1)))
659 x >>= 4, pos += 4;
660 if (!(x & ((((uint64_t)1) << 2) - 1)))
661 x >>= 2, pos += 2;
662 if (!(x & ((((uint64_t)1) << 1) - 1)))
663 x >>= 1, pos += 1;
664
665 len = 0;
666 if (!(~x & ((((uint64_t)1) << 32) - 1)))
667 x >>= 32, len += 32;
668 if (!(~x & ((((uint64_t)1) << 16) - 1)))
669 x >>= 16, len += 16;
670 if (!(~x & ((((uint64_t)1) << 8) - 1)))
671 x >>= 8, len += 8;
672 if (!(~x & ((((uint64_t)1) << 4) - 1)))
673 x >>= 4, len += 4;
674 if (!(~x & ((((uint64_t)1) << 2) - 1)))
675 x >>= 2, len += 2;
676 if (!(~x & ((((uint64_t)1) << 1) - 1)))
677 x >>= 1, len += 1;
678
679 if (x)
680 return -1;
681 if (neg) {
682 pos = (pos + len) & (rep - 1);
683 len = rep - len;
684 }
685 return ((0x1000 & rep << 6) | (((rep - 1) ^ 31) << 1 & 63) |
686 ((rep - pos) & (rep - 1)) << 6 | (len - 1));
687}
688
689static void gen_logical_imm(uint32_t opcode, int rd, int rn,
690 uint64_t imm, int is_64bit)
691{
692 uint32_t instr;
693 uint64_t val;
694 int enc;
695
696 if (is_64bit)
697 val = imm;
698 else {
699 val = (uint32_t)imm;
700 val |= val << 32;
701 }
702
703 enc = arm64_asm_encode_bimm64(val);
704 if (enc < 0) {
705 tcc_error("logical immediate out of range");
706 return;
707 }
708
709 instr = opcode;
710 if (is_64bit)
711 instr |= ARM64_SF(1);
712 instr |= ARM64_N(enc >> 12);
713 instr |= ARM64_IMM_R(enc >> 6);
714 instr |= ARM64_IMM_S(enc);
715 instr |= ARM64_RN(rn);
716 instr |= ARM64_RD(rd);
717 emit_instr32(instr);
718}
719
720/* return the constraint priority (we allocate first the lowest
721 numbered constraints) */
722static inline int constraint_priority(const char *str)
723{
724 int priority, c, pr;
725
726 priority = 0;
727 for (;;) {
728 c = *str++;
729 if (c == '\0')
730 break;
731 switch (c) {
732 case '=':
733 case '+':
734 case '&':
735 continue;
736 case 'r':
737 pr = 1;
738 break;
739 case 'w':
740 case 'f':
741 case 'x':
742 case 'y':
743 pr = 3;
744 break;
745 case 'm':
746 case 'Q':
747 pr = 4;
748 break;
749 case 'i':
750 case 'S':
751 pr = 5;
752 break;
753 case 'U':
754 if (str[0] == 'm' && str[1] == 'p') {
755 str += 2;
756 pr = 4;
757 break;
758 }
759 tcc_warning("unknown constraint '%c'", c);
760 pr = 0;
761 break;
762 case 'I':
763 case 'J':
764 case 'K':
765 case 'L':
766 case 'M':
767 case 'N':
768 case 'Z':
769 pr = 6;
770 break;
771 case 'n':
772 pr = 7;
773 break;
774 case 'g':
775 pr = 8;
776 break;
777 default:
778 tcc_warning("unknown constraint '%c'", c);
779 pr = 0;
780 break;
781 }
782 if (pr > priority)
783 priority = pr;
784 }
785 return priority;
786}
787
788static const char *skip_constraint_modifiers(const char *p)
789{
790 while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
791 p++;
792 return p;
793}
794
795static int is_valid_add_imm(int64_t val)
796{
797 return val >= 0 && val <= 4095;
798}
799
800static int is_valid_logical_imm(int64_t val, int bits)
801{
802 uint64_t uval;
803
804 uval = (uint64_t)val;
805 if (bits == 32) {
806 uval = (uint32_t)uval;
807 uval |= uval << 32;
808 }
809 return arm64_asm_encode_bimm64(uval) >= 0;
810}
811
812static int is_valid_movw_imm(int64_t val)
813{
814 uint64_t uval = (uint64_t)val;
815
816 if (uval <= 0xFFFF)
817 return 1;
818 if (uval >= 0xFFFF0000 && (uval & 0xFFFF) == 0)
819 return 1;
820 if (uval >= 0xFFFF00000000ULL && (uval & 0xFFFFFFFFULL) == 0)
821 return 1;
822 if ((uval & 0xFFFFFFFF00000000ULL) == 0)
823 return 1;
824
825 return 0;
826}
827
828static int is_valid_movw_shift(int shift, int is_64bit)
829{
830 if (shift < 0 || (shift & 15))
831 return 0;
832 if (shift > (is_64bit ? 48 : 16))
833 return 0;
834 return 1;
835}
836
837static int arm64_memory_is_base_only(const SValue *sv)
838{
839 int r;
840
841 r = sv->r;
842 if ((r & VT_VALMASK) == VT_CONST)
843 return 0;
844 if ((r & VT_VALMASK) == VT_LOCAL)
845 return 0;
846 if ((r & VT_VALMASK) == VT_LLOCAL)
847 return 1;
848 if (r & VT_LVAL)
849 return (r & VT_VALMASK) < VT_CONST;
850 return 0;
851}
852
853static int arm64_memory_is_pair_suitable(const SValue *sv)
854{
855 int64_t offset;
856
857 if (arm64_memory_is_base_only(sv))
858 return 1;
859 if ((sv->r & VT_VALMASK) != VT_LOCAL)
860 return 0;
861
862 offset = (int64_t)sv->c.i;
863 return (offset & 7) == 0 && offset >= -512 && offset <= 504;
864}
865
866static int arm64_int_reg_is_allocatable(int reg)
867{
868#ifdef TCC_TARGET_PE
869 return reg >= TREG_X0 && reg <= TREG_X17;
870#else
871 return reg >= TREG_X0 && reg <= TREG_X30;
872#endif
873}
874
875static int arm64_memory_needs_address_reg(const SValue *sv)
876{
877 int r;
878
879 r = sv->r & ~(VT_BOUNDED | VT_NONCONST);
880 if (!(r & VT_LVAL))
881 return 0;
882 switch (r & VT_VALMASK) {
883 case VT_LOCAL:
884 case VT_LLOCAL:
885 case VT_CONST:
886 return 1;
887 }
888 return 0;
889}
890
891static int arm64_prepare_memory_operand(ASMOperand *op, uint8_t *regs_allocated)
892{
893 int reg;
894
895 if (!arm64_memory_needs_address_reg(op->vt))
896 return 1;
897
898 for (reg = 0; reg < 31; reg++) {
899 if (arm64_int_reg_is_allocatable(reg)
900 && !(regs_allocated[reg] & REG_IN_MASK)) {
901 regs_allocated[reg] |= REG_IN_MASK;
902 op->reg = reg;
903 op->is_memory = 1;
904 return 1;
905 }
906 }
907 return 0;
908}
909
910static void arm64_load_memory_operand_base(int reg, SValue *sv)
911{
912 SValue base;
913 int rval;
914
915 base = *sv;
916 base.type.t = VT_PTR;
917 rval = base.r & VT_VALMASK;
918 if (rval == VT_LLOCAL) {
919 base.r = (base.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
920 } else if (rval == VT_CONST || rval == VT_LOCAL) {
921 base.r &= ~VT_LVAL;
922 } else {
923 tcc_internal_error("unsupported ARM64 memory operand base");
924 }
925 load(reg, &base);
926}
927
928static int operand_is_sp(const Operand *op)
929{
930 return op->reg_tok == TOK_ASM_sp;
931}
932
933static int parse_sysreg_name(int t)
934{
935 const char *name;
936
937 if (t < TOK_IDENT)
938 return -1;
939 name = get_tok_str(t, NULL);
940 if (!strcmp(name, "FPCR") || !strcmp(name, "fpcr"))
941 return 0;
942 if (!strcmp(name, "FPSR") || !strcmp(name, "fpsr"))
943 return 1;
944 return -1;
945}
946
947static void gen_mrs(int rt, int sysreg)
948{
949 uint32_t instr;
950
951 switch (sysreg) {
952 case 0: /* FPCR */
953 instr = ARM64_MRS_FPCR;
954 break;
955 case 1: /* FPSR */
956 instr = ARM64_MRS_FPSR;
957 break;
958 default:
959 tcc_error("unsupported system register");
960 return;
961 }
962 emit_instr32(instr | ARM64_RD(rt));
963}
964
965static void gen_msr(int rt, int sysreg)
966{
967 uint32_t instr;
968
969 switch (sysreg) {
970 case 0: /* FPCR */
971 instr = ARM64_MSR_FPCR;
972 break;
973 case 1: /* FPSR */
974 instr = ARM64_MSR_FPSR;
975 break;
976 default:
977 tcc_error("unsupported system register");
978 return;
979 }
980 emit_instr32(instr | ARM64_RD(rt));
981}
982
983/* Generate NOP */
984static void gen_nop(void)
985{
986 emit_instr32(ARM64_NOP);
987}
988
989/* Generate shift operations (LSL, LSR, ASR, ROR) */
990static void gen_shift(int rd, int rn, int rm_or_imm, int shift_type, int is_imm, int is_64bit)
991{
992 uint32_t instr;
993 int width = is_64bit ? 64 : 32;
994
995 if (is_imm) {
996 /* Shift by immediate */
997 switch (shift_type) {
998 case 0: /* LSL - UBFM alias */
999 if (rm_or_imm < 0 || rm_or_imm >= width) {
1000 tcc_error("shift immediate out of range");
1001 return;
1002 }
1003 instr = is_64bit ? ARM64_LSL_IMM : ARM64_LSR_IMM_32;
1004 instr |= ARM64_IMM_R((width - rm_or_imm) & (width - 1));
1005 instr |= ARM64_IMM_S(width - rm_or_imm - 1);
1006 break;
1007 case 1: /* LSR - UBFM alias: immr = shift, imms = width - 1 */
1008 if (rm_or_imm < 0 || rm_or_imm >= width) {
1009 tcc_error("shift immediate out of range");
1010 return;
1011 }
1012 instr = is_64bit ? ARM64_LSL_IMM : ARM64_LSR_IMM_32;
1013 instr |= ARM64_IMM_R(rm_or_imm);
1014 instr |= ARM64_IMM_S(width - 1);
1015 break;
1016 case 2: /* ASR - SBFM alias: immr = shift, imms = width - 1 */
1017 if (rm_or_imm < 0 || rm_or_imm >= width) {
1018 tcc_error("shift immediate out of range");
1019 return;
1020 }
1021 instr = is_64bit ? ARM64_ASR_IMM : (ARM64_ASR_IMM & ~(1U << 31));
1022 instr |= ARM64_IMM_R(rm_or_imm);
1023 instr |= ARM64_IMM_S(width - 1);
1024 break;
1025 case 3: /* ROR - EXTR alias: Rm = source, Rn = source, imms = shift */
1026 if (rm_or_imm < 0 || rm_or_imm >= width) {
1027 tcc_error("shift immediate out of range");
1028 return;
1029 }
1030 instr = is_64bit ? ARM64_EXTR64 : ARM64_EXTR;
1031 instr |= ARM64_RM(rn);
1032 instr |= ARM64_IMM_S(rm_or_imm);
1033 instr |= ARM64_RN(rn);
1034 instr |= ARM64_RD(rd);
1035 emit_instr32(instr);
1036 return;
1037 default:
1038 tcc_error("unknown shift type");
1039 return;
1040 }
1041 instr |= ARM64_RN(rn);
1042 instr |= ARM64_RD(rd);
1043 } else {
1044 /* Shift by register */
1045 switch (shift_type) {
1046 case 0: /* LSL */
1047 instr = ARM64_LSL_REG;
1048 break;
1049 case 1: /* LSR */
1050 instr = ARM64_LSR_REG;
1051 break;
1052 case 2: /* ASR */
1053 instr = ARM64_ASR_REG;
1054 break;
1055 case 3: /* ROR */
1056 instr = ARM64_ROR_REG;
1057 break;
1058 default:
1059 tcc_error("unknown shift type");
1060 return;
1061 }
1062 if (is_64bit)
1063 instr |= ARM64_SF(1);
1064 instr |= ARM64_RM(rm_or_imm);
1065 instr |= ARM64_RN(rn);
1066 instr |= ARM64_RD(rd);
1067 }
1068 emit_instr32(instr);
1069}
1070
1071/* Handle shift instructions */
1072static void asm_shift(TCCState *s1, int token)
1073{
1074 Operand op1, op2, op3;
1075 int rd, rn, shift_amount;
1076 int shift_type;
1077 int is_64bit = 1;
1078
1079 switch (token) {
1080 case TOK_ASM_lsl:
1081 shift_type = 0;
1082 break;
1083 case TOK_ASM_lsr:
1084 shift_type = 1;
1085 break;
1086 case TOK_ASM_asr:
1087 shift_type = 2;
1088 break;
1089 case TOK_ASM_ror:
1090 shift_type = 3;
1091 break;
1092 default:
1093 tcc_error("unknown shift instruction");
1094 return;
1095 }
1096
1097 parse_operand(s1, &op1);
1098 if (tok == ',') next();
1099 parse_operand(s1, &op2);
1100
1101 if (!(op1.type & OP_REG)) {
1102 tcc_error("expected register in first operand");
1103 return;
1104 }
1105 if (!(op2.type & OP_REG)) {
1106 tcc_error("expected register in second operand");
1107 return;
1108 }
1109
1110 rd = op1.reg;
1111 rn = op2.reg;
1112
1113 if (tok == ',') {
1114 next();
1115 parse_operand(s1, &op3);
1116 is_64bit = (op1.reg_type & REG_X);
1117 if (is_64bit != !!(op2.reg_type & REG_X)) {
1118 tcc_error("mismatched register widths");
1119 return;
1120 }
1121 if (op3.type & OP_REG) {
1122 if (is_64bit != !!(op3.reg_type & REG_X)) {
1123 tcc_error("mismatched register widths");
1124 return;
1125 }
1126 gen_shift(rd, rn, op3.reg, shift_type, 0, is_64bit);
1127 } else if (op3.type & OP_IM) {
1128 shift_amount = op3.e.v;
1129 gen_shift(rd, rn, shift_amount, shift_type, 1, is_64bit);
1130 } else {
1131 tcc_error("shift requires immediate or register operand");
1132 }
1133 } else {
1134 tcc_error("shift requires immediate or register operand");
1135 return;
1136 }
1137}
1138
1139/* Generate barrier instructions (ISB, DSB, DMB) */
1140static void gen_barrier(int barrier_type, int option)
1141{
1142 uint32_t instr;
1143
1144 switch (barrier_type) {
1145 case 0: /* ISB - Instruction Synchronization Barrier */
1146 instr = ARM64_ISB;
1147 break;
1148 case 1: /* DSB - Data Synchronization Barrier */
1149 instr = ARM64_DSB;
1150 break;
1151 case 2: /* DMB - Data Memory Barrier */
1152 instr = ARM64_DMB;
1153 break;
1154 default:
1155 tcc_error("unknown barrier type");
1156 return;
1157 }
1158 instr |= ARM64_ISB_OPTION(option);
1159 emit_instr32(instr);
1160}
1161
1162/* Handle barrier instructions */
1163static void asm_barrier(TCCState *s1, int token)
1164{
1165 int barrier_type, option;
1166 Operand op;
1167
1168 switch (token) {
1169 case TOK_ASM_isb:
1170 barrier_type = 0;
1171 break;
1172 case TOK_ASM_dsb:
1173 barrier_type = 1;
1174 break;
1175 case TOK_ASM_dmb:
1176 barrier_type = 2;
1177 break;
1178 default:
1179 tcc_error("unknown barrier instruction");
1180 return;
1181 }
1182
1183 /* Default option = sy/full system. */
1184 option = 0xF;
1185
1186 /* Check for an optional named or numeric barrier scope. */
1187 if (tok != TOK_LINEFEED) {
1188 option = parse_barrier_option_name(tok);
1189 if (option >= 0) {
1190 next();
1191 } else {
1192 parse_operand(s1, &op);
1193 if (!(op.type & OP_IM) || op.e.sym) {
1194 tcc_error("barrier option must be an immediate or scope name");
1195 return;
1196 }
1197 if (op.e.v > 0xF) {
1198 tcc_error("barrier option out of range");
1199 return;
1200 }
1201 option = op.e.v;
1202 }
1203 }
1204
1205 gen_barrier(barrier_type, option);
1206}
1207
1208/* Generate immediate move sequence */
1209static void gen_mov_imm(int rd, uint64_t imm, int is_64bit)
1210{
1211 uint16_t hw;
1212 int i, first = 1;
1213
1214 for (i = 0; i < (is_64bit ? 4 : 2); i++) {
1215 hw = (imm >> (i * 16)) & 0xFFFF;
1216 if (hw != 0 || i == 0) {
1217 if (first) {
1218 /* Pass halfword index (0-3), not bit count */
1219 gen_movz(rd, hw, i, is_64bit);
1220 first = 0;
1221 } else {
1222 gen_movk(rd, hw, i, is_64bit);
1223 }
1224 } else if (!first) {
1225 gen_movk(rd, hw, i, is_64bit);
1226 }
1227 }
1228}
1229
1230/* Handle mov instruction */
1231static void asm_mov(TCCState *s1)
1232{
1233 Operand op1, op2;
1234 int rd, rn;
1235 int is_64bit;
1236
1237 parse_operand(s1, &op1);
1238 if (tok == ',') next();
1239 parse_operand(s1, &op2);
1240 rd = op1.reg;
1241 is_64bit = (op1.reg_type & REG_X);
1242
1243 if (op2.type & OP_IM) {
1244 /* Handle immediate: mov x0, #123 */
1245 if (operand_is_sp(&op1)) {
1246 tcc_error("cannot move an immediate into sp");
1247 return;
1248 }
1249 gen_mov_imm(rd, op2.e.v, is_64bit);
1250 } else if (op2.type & OP_REG) {
1251 /* Handle register: mov x0, x1 */
1252 rn = op2.reg;
1253 if (operand_is_sp(&op1) || operand_is_sp(&op2))
1254 gen_add_imm(rd, rn, 0, 1, 0);
1255 else
1256 gen_mov_reg(rd, rn, is_64bit);
1257 } else {
1258 tcc_error("invalid operand for mov");
1259 }
1260}
1261
1262/* Handle data processing instructions */
1263static void asm_data_proc(TCCState *s1, int token)
1264{
1265 Operand op1, op2, op3;
1266 int rd, rn, rm;
1267 int is_64bit = 1;
1268 uint32_t opcode;
1269
1270 switch (token) {
1271 case TOK_ASM_add:
1272 case TOK_ASM_adds:
1273 opcode = token == TOK_ASM_add ? ARM64_ADD_REG : ARM64_ADDS_REG;
1274 break;
1275 case TOK_ASM_sub:
1276 case TOK_ASM_subs:
1277 opcode = token == TOK_ASM_sub ? ARM64_SUB_REG : ARM64_SUBS_REG;
1278 break;
1279 case TOK_ASM_and:
1280 case TOK_ASM_ands:
1281 opcode = token == TOK_ASM_and ? ARM64_AND_REG : ARM64_ANDS_REG;
1282 break;
1283 case TOK_ASM_orr:
1284 opcode = ARM64_ORR_REG;
1285 break;
1286 case TOK_ASM_eor:
1287 opcode = ARM64_EOR_REG;
1288 break;
1289 case TOK_ASM_mul:
1290 opcode = ARM64_MUL_REG;
1291 break;
1292 default:
1293 tcc_error("unsupported data processing instruction");
1294 return;
1295 }
1296
1297 parse_operand(s1, &op1);
1298 if (tok == ',') next();
1299 parse_operand(s1, &op2);
1300
1301 if (!(op1.type & OP_REG)) {
1302 tcc_error("expected register in first operand");
1303 return;
1304 }
1305 if (!(op2.type & OP_REG)) {
1306 tcc_error("expected register in second operand");
1307 return;
1308 }
1309
1310 rd = op1.reg;
1311 rn = op2.reg;
1312
1313 if (tok == ',') {
1314 next();
1315 parse_operand(s1, &op3);
1316 is_64bit = (op1.reg_type & REG_X);
1317 if (is_64bit != !!(op2.reg_type & REG_X)) {
1318 tcc_error("mismatched register widths");
1319 return;
1320 }
1321 if (op3.type & OP_IM) {
1322 if (token == TOK_ASM_add || token == TOK_ASM_adds)
1323 gen_add_imm(rd, rn, op3.e.v, is_64bit,
1324 token == TOK_ASM_adds);
1325 else if (token == TOK_ASM_sub || token == TOK_ASM_subs)
1326 gen_sub_imm(rd, rn, op3.e.v, is_64bit,
1327 token == TOK_ASM_subs);
1328 else if (token == TOK_ASM_and)
1329 gen_logical_imm(ARM64_AND_IMM, rd, rn, op3.e.v, is_64bit);
1330 else if (token == TOK_ASM_ands)
1331 gen_logical_imm(ARM64_ANDS_IMM, rd, rn, op3.e.v, is_64bit);
1332 else if (token == TOK_ASM_orr)
1333 gen_logical_imm(ARM64_ORR_IMM_BASE, rd, rn, op3.e.v, is_64bit);
1334 else if (token == TOK_ASM_eor)
1335 gen_logical_imm(ARM64_EOR_IMM, rd, rn, op3.e.v, is_64bit);
1336 else
1337 tcc_error("immediate operand not valid for this instruction");
1338 } else {
1339 if (!(op3.type & OP_REG)) {
1340 tcc_error("expected register in third operand");
1341 return;
1342 }
1343 rm = op3.reg;
1344 if (is_64bit != !!(op2.reg_type & REG_X) || is_64bit != !!(op3.reg_type & REG_X)) {
1345 tcc_error("mismatched register widths");
1346 return;
1347 }
1348 gen_dp_reg(opcode, rd, rn, rm, is_64bit);
1349 }
1350 } else if (op2.type & OP_IM) {
1351 tcc_error("missing source register for immediate form");
1352 } else {
1353 tcc_error("missing third operand");
1354 }
1355}
1356
1357/* Handle load/store instructions */
1358static void asm_ldst(TCCState *s1, int token)
1359{
1360 Operand op1, op2;
1361 int rt, rn;
1362 int32_t offset = 0;
1363 int size_log2 = 3;
1364 uint32_t base_opcode;
1365
1366 parse_operand(s1, &op1);
1367 if (tok == ',') next();
1368 parse_operand(s1, &op2);
1369
1370 if (!(op1.type & OP_REG)) {
1371 tcc_error("expected register in first operand");
1372 return;
1373 }
1374 if (op2.type != OP_ADDR) {
1375 tcc_error("expected address operand in second operand");
1376 return;
1377 }
1378
1379 rt = op1.reg;
1380 rn = op2.reg;
1381 offset = op2.e.v;
1382
1383 switch (token) {
1384 case TOK_ASM_ldr:
1385 if (op1.reg_type & REG_X) {
1386 base_opcode = ARM64_LDR_X;
1387 size_log2 = 3;
1388 } else if (op1.reg_type & REG_W) {
1389 base_opcode = ARM64_LDR_W;
1390 size_log2 = 2;
1391 } else if (op1.reg_type & REG_D) {
1392 base_opcode = ARM64_LDR_D;
1393 size_log2 = 3;
1394 } else {
1395 tcc_error("ldr requires a w, x, or d register");
1396 return;
1397 }
1398 break;
1399 case TOK_ASM_ldrb:
1400 base_opcode = ARM64_LDR_B;
1401 size_log2 = 0;
1402 break;
1403 case TOK_ASM_ldrh:
1404 base_opcode = ARM64_LDR_H;
1405 size_log2 = 1;
1406 break;
1407 case TOK_ASM_str:
1408 if (op1.reg_type & REG_X) {
1409 base_opcode = ARM64_STR_X;
1410 size_log2 = 3;
1411 } else if (op1.reg_type & REG_W) {
1412 base_opcode = ARM64_STR_W;
1413 size_log2 = 2;
1414 } else if (op1.reg_type & REG_D) {
1415 base_opcode = ARM64_STR_D;
1416 size_log2 = 3;
1417 } else {
1418 tcc_error("str requires a w, x, or d register");
1419 return;
1420 }
1421 break;
1422 case TOK_ASM_strb:
1423 base_opcode = ARM64_STR_B;
1424 size_log2 = 0;
1425 break;
1426 case TOK_ASM_strh:
1427 base_opcode = ARM64_STR_H;
1428 size_log2 = 1;
1429 break;
1430 default:
1431 tcc_error("unsupported load/store instruction");
1432 return;
1433 }
1434
1435 if (op2.addr_mode != ADDR_OFF)
1436 tcc_error("only offset addressing is implemented for ldr/str");
1437 gen_ldst_imm(base_opcode, rt, rn, offset, size_log2);
1438}
1439
1440static void asm_ldst_pair(TCCState *s1, int token)
1441{
1442 Operand op1, op2, op3;
1443 uint32_t base_opcode;
1444 int size_log2 = 3;
1445
1446 parse_operand(s1, &op1);
1447 if (tok == ',')
1448 next();
1449 parse_operand(s1, &op2);
1450 if (tok == ',')
1451 next();
1452 parse_operand(s1, &op3);
1453
1454 if (!(op1.type & OP_REG)) {
1455 tcc_error("expected register in first operand");
1456 return;
1457 }
1458 if (!(op2.type & OP_REG)) {
1459 tcc_error("expected register in second operand");
1460 return;
1461 }
1462 if (!(op3.type & OP_ADDR))
1463 tcc_error("pair load/store requires an address operand");
1464
1465 if ((op1.reg_type & REG_X) && (op2.reg_type & REG_X)) {
1466 if (token == TOK_ASM_stp) {
1467 base_opcode = op3.addr_mode == ADDR_PRE ? ARM64_STP_X_PRE :
1468 op3.addr_mode == ADDR_POST ? ARM64_STP_X_POST :
1469 ARM64_STP_X;
1470 } else {
1471 base_opcode = op3.addr_mode == ADDR_PRE ? ARM64_LDP_X_PRE :
1472 op3.addr_mode == ADDR_POST ? ARM64_LDP_X_POST :
1473 ARM64_LDP_X;
1474 }
1475 } else if ((op1.reg_type & REG_D) && (op2.reg_type & REG_D)) {
1476 if (token == TOK_ASM_stp) {
1477 base_opcode = op3.addr_mode == ADDR_PRE ? ARM64_STP_D_PRE :
1478 op3.addr_mode == ADDR_POST ? ARM64_STP_D_POST :
1479 ARM64_STP_D;
1480 } else {
1481 base_opcode = op3.addr_mode == ADDR_PRE ? ARM64_LDP_D_PRE :
1482 op3.addr_mode == ADDR_POST ? ARM64_LDP_D_POST :
1483 ARM64_LDP_D;
1484 }
1485 } else {
1486 tcc_error("stp/ldp requires matching x or d registers");
1487 return;
1488 }
1489
1490 gen_ldst_pair(base_opcode, op1.reg, op2.reg, op3.reg, op3.e.v, size_log2);
1491}
1492
1493static void asm_sysreg(TCCState *s1, int token)
1494{
1495 Operand op;
1496 int sysreg;
1497
1498 if (token == TOK_ASM_mrs) {
1499 parse_operand(s1, &op);
1500 if (tok == ',')
1501 next();
1502 sysreg = parse_sysreg_name(tok);
1503 if (sysreg < 0)
1504 tcc_error("unsupported system register");
1505 next();
1506 gen_mrs(op.reg, sysreg);
1507 return;
1508 }
1509
1510 sysreg = parse_sysreg_name(tok);
1511 if (sysreg < 0)
1512 tcc_error("unsupported system register");
1513 next();
1514 if (tok == ',')
1515 next();
1516 parse_operand(s1, &op);
1517 gen_msr(op.reg, sysreg);
1518}
1519
1520/* Get condition code from branch instruction token */
1521static int get_branch_condition(int branch_token)
1522{
1523 int cond_token;
1524
1525 /* Map branch token to condition token (strip 'b' prefix) */
1526 switch (branch_token) {
1527 case TOK_ASM_beq: cond_token = TOK_ASM_eq; break;
1528 case TOK_ASM_bne: cond_token = TOK_ASM_ne; break;
1529 case TOK_ASM_bcs:
1530 case TOK_ASM_bhs: cond_token = TOK_ASM_cs; break;
1531 case TOK_ASM_bcc:
1532 case TOK_ASM_blo: cond_token = TOK_ASM_cc; break;
1533 case TOK_ASM_bmi: cond_token = TOK_ASM_mi; break;
1534 case TOK_ASM_bpl: cond_token = TOK_ASM_pl; break;
1535 case TOK_ASM_bvs: cond_token = TOK_ASM_vs; break;
1536 case TOK_ASM_bvc: cond_token = TOK_ASM_vc; break;
1537 case TOK_ASM_bhi: cond_token = TOK_ASM_hi; break;
1538 case TOK_ASM_bls: cond_token = TOK_ASM_ls; break;
1539 case TOK_ASM_bge: cond_token = TOK_ASM_ge; break;
1540 case TOK_ASM_blt: cond_token = TOK_ASM_lt; break;
1541 case TOK_ASM_bgt: cond_token = TOK_ASM_gt; break;
1542 case TOK_ASM_ble: cond_token = TOK_ASM_le; break;
1543 default: return -1;
1544 }
1545
1546 return parse_condition(cond_token);
1547}
1548
1549/* Handle branch instructions */
1550static void asm_branch(TCCState *s1, int token)
1551{
1552 Operand op;
1553 int cond;
1554 Sym *sym;
1555 int32_t offset;
1556
1557 /* ret can be used without operand */
1558 if (token == TOK_ASM_ret && (tok == TOK_LINEFEED || tok == ';' || tok == TOK_EOF)) {
1559 gen_ret(30); /* x30 is the link register */
1560 return;
1561 }
1562
1563 if (token == TOK_ASM_br || token == TOK_ASM_blr || token == TOK_ASM_ret)
1564 parse_operand(s1, &op);
1565 else
1566 parse_expr_operand(s1, &op);
1567
1568 if (op.type & OP_IM) {
1569 sym = op.e.sym;
1570 if (sym) {
1571 /* Symbolic address - emit relocation */
1572 offset = 0;
1573
1574 cond = get_branch_condition(token);
1575 if (cond >= 0) {
1576 /* Conditional branch - use CONDBR19 relocation */
1577 gen_b_cond(cond, 0);
1578 greloca(cur_text_section, sym, ind - 4, R_AARCH64_CONDBR19, 0);
1579 } else {
1580 switch (token) {
1581 case TOK_ASM_b:
1582 gen_b(0);
1583 greloca(cur_text_section, sym, ind - 4, R_AARCH64_JUMP26, 0);
1584 break;
1585 case TOK_ASM_bl:
1586 gen_bl(0);
1587 greloca(cur_text_section, sym, ind - 4, R_AARCH64_CALL26, 0);
1588 break;
1589 default:
1590 tcc_error("unsupported branch");
1591 }
1592 }
1593 } else {
1594 offset = (int32_t)op.e.v - ind;
1595
1596 cond = get_branch_condition(token);
1597 if (cond >= 0) {
1598 gen_b_cond(cond, offset);
1599 } else {
1600 switch (token) {
1601 case TOK_ASM_b:
1602 gen_b(offset);
1603 break;
1604 case TOK_ASM_bl:
1605 gen_bl(offset);
1606 break;
1607 default:
1608 tcc_error("unsupported branch");
1609 }
1610 }
1611 }
1612 } else if (op.type & OP_REG) {
1613 switch (token) {
1614 case TOK_ASM_br:
1615 gen_br(op.reg);
1616 break;
1617 case TOK_ASM_blr:
1618 gen_blr(op.reg);
1619 break;
1620 case TOK_ASM_ret:
1621 gen_ret(op.reg);
1622 break;
1623 default:
1624 tcc_error("register branch not valid");
1625 }
1626 }
1627}
1628
1629/* Handle CBZ/CBNZ */
1630static void asm_cb(TCCState *s1, int token)
1631{
1632 Operand op1, op2;
1633 int rt, is_64bit;
1634 int32_t offset;
1635 Sym *sym;
1636
1637 parse_operand(s1, &op1);
1638 if (tok == ',') next();
1639 parse_expr_operand(s1, &op2);
1640
1641 rt = op1.reg;
1642 is_64bit = (op1.reg_type & REG_X);
1643 sym = op2.e.sym;
1644
1645 if (sym) {
1646 /* Symbolic address - emit relocation */
1647 offset = 0;
1648 if (token == TOK_ASM_cbz) {
1649 gen_cbz(rt, offset, is_64bit);
1650 greloca(cur_text_section, sym, ind - 4, R_AARCH64_CONDBR19, 0);
1651 } else {
1652 gen_cbnz(rt, offset, is_64bit);
1653 greloca(cur_text_section, sym, ind - 4, R_AARCH64_CONDBR19, 0);
1654 }
1655 } else {
1656 offset = (int32_t)op2.e.v - ind;
1657 if (token == TOK_ASM_cbz)
1658 gen_cbz(rt, offset, is_64bit);
1659 else
1660 gen_cbnz(rt, offset, is_64bit);
1661 }
1662}
1663
1664/* Handle MOVZ/MOVN/MOVK */
1665static void asm_move_wide(TCCState *s1, int token)
1666{
1667 Operand op1, op2;
1668 int rd, is_64bit = 1;
1669 uint16_t imm;
1670 int shift = 0;
1671
1672 parse_operand(s1, &op1);
1673 if (tok == ',') next();
1674 parse_operand(s1, &op2);
1675
1676 if (!(op1.type & OP_REG)) {
1677 tcc_error("expected register in first operand");
1678 return;
1679 }
1680 if (!(op2.type & OP_IM) || op2.e.sym) {
1681 tcc_error("expected immediate in second operand");
1682 return;
1683 }
1684
1685 rd = op1.reg;
1686 is_64bit = (op1.reg_type & REG_X);
1687 if ((uint64_t)op2.e.v > 0xFFFF) {
1688 tcc_error("move wide immediate out of range");
1689 return;
1690 }
1691 imm = op2.e.v;
1692
1693 if (tok == ',') {
1694 next();
1695 if (tok != TOK_ASM_lsl) {
1696 tcc_error("move wide shift must use lsl");
1697 return;
1698 }
1699 next();
1700 if (tok == '#') next();
1701 asm_expr(s1, &op2.e);
1702 if (op2.e.sym || !is_valid_movw_shift((int)op2.e.v, is_64bit)) {
1703 tcc_error("move wide shift out of range");
1704 return;
1705 }
1706 shift = (int)op2.e.v / 16;
1707 }
1708
1709 switch (token) {
1710 case TOK_ASM_movz:
1711 gen_movz(rd, imm, shift, is_64bit);
1712 break;
1713 case TOK_ASM_movn:
1714 gen_movn(rd, imm, shift, is_64bit);
1715 break;
1716 case TOK_ASM_movk:
1717 gen_movk(rd, imm, shift, is_64bit);
1718 break;
1719 default:
1720 tcc_error("unknown move wide instruction");
1721 }
1722}
1723
1724/* Main assembler opcode dispatcher */
57ST_FUNC void asm_opcode(TCCState *s1, int opcode)1725ST_FUNC void asm_opcode(TCCState *s1, int opcode)
58{1726{
59 asm_error();1727 switch (opcode) {
1728 case TOK_ASM_add:
1729 case TOK_ASM_adds:
1730 case TOK_ASM_sub:
1731 case TOK_ASM_subs:
1732 case TOK_ASM_and:
1733 case TOK_ASM_ands:
1734 case TOK_ASM_orr:
1735 case TOK_ASM_eor:
1736 case TOK_ASM_mul:
1737 asm_data_proc(s1, opcode);
1738 break;
1739
1740 case TOK_ASM_mov:
1741 /* mov is handled separately - it's ORR with zero register */
1742 asm_mov(s1);
1743 break;
1744
1745 case TOK_ASM_lsl:
1746 case TOK_ASM_lsr:
1747 case TOK_ASM_asr:
1748 case TOK_ASM_ror:
1749 asm_shift(s1, opcode);
1750 break;
1751
1752 case TOK_ASM_ldr:
1753 case TOK_ASM_ldrb:
1754 case TOK_ASM_ldrh:
1755 case TOK_ASM_str:
1756 case TOK_ASM_strb:
1757 case TOK_ASM_strh:
1758 asm_ldst(s1, opcode);
1759 break;
1760
1761 case TOK_ASM_ldp:
1762 case TOK_ASM_stp:
1763 asm_ldst_pair(s1, opcode);
1764 break;
1765
1766 case TOK_ASM_b:
1767 case TOK_ASM_bl:
1768 case TOK_ASM_br:
1769 case TOK_ASM_blr:
1770 case TOK_ASM_ret:
1771 case TOK_ASM_beq:
1772 case TOK_ASM_bne:
1773 case TOK_ASM_bcs:
1774 case TOK_ASM_bhs:
1775 case TOK_ASM_bcc:
1776 case TOK_ASM_blo:
1777 case TOK_ASM_bmi:
1778 case TOK_ASM_bpl:
1779 case TOK_ASM_bvs:
1780 case TOK_ASM_bvc:
1781 case TOK_ASM_bhi:
1782 case TOK_ASM_bls:
1783 case TOK_ASM_bge:
1784 case TOK_ASM_blt:
1785 case TOK_ASM_bgt:
1786 case TOK_ASM_ble:
1787 asm_branch(s1, opcode);
1788 break;
1789
1790 case TOK_ASM_cbz:
1791 case TOK_ASM_cbnz:
1792 asm_cb(s1, opcode);
1793 break;
1794
1795 case TOK_ASM_movz:
1796 case TOK_ASM_movn:
1797 case TOK_ASM_movk:
1798 asm_move_wide(s1, opcode);
1799 break;
1800
1801 case TOK_ASM_mrs:
1802 case TOK_ASM_msr:
1803 asm_sysreg(s1, opcode);
1804 break;
1805
1806 case TOK_ASM_isb:
1807 case TOK_ASM_dsb:
1808 case TOK_ASM_dmb:
1809 asm_barrier(s1, opcode);
1810 break;
1811
1812 case TOK_ASM_nop:
1813 gen_nop();
1814 break;
1815
1816 default:
1817 tcc_error("ARM64 instruction '%s' not implemented",
1818 get_tok_str(opcode, NULL));
1819 break;
1820 }
60}1821}
61 1822
1823/* Substitute assembler operand */
62ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)1824ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
63{1825{
64 asm_error();1826 int r, reg, size, fp_reg, align;
1827 int64_t val;
1828 uint64_t uval;
1829
1830 r = sv->r;
1831 if ((r & VT_VALMASK) == VT_CONST) {
1832 if ((modifier == 'w' || modifier == 'x') && !(r & VT_LVAL)
1833 && !(r & VT_SYM) && sv->c.i == 0) {
1834 cstr_cat(add_str, modifier == 'w' ? "wzr" : "xzr", -1);
1835 return;
1836 }
1837 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' &&
1838 modifier != 'P')
1839 cstr_ccat(add_str, '#');
1840 if (r & VT_SYM) {
1841 const char *name = get_tok_str(sv->sym->v, NULL);
1842 if (sv->sym->v >= SYM_FIRST_ANOM)
1843 get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
1844 if (tcc_state->leading_underscore)
1845 cstr_ccat(add_str, '_');
1846 cstr_cat(add_str, name, -1);
1847 if ((uint32_t) sv->c.i == 0)
1848 goto no_offset;
1849 cstr_ccat(add_str, '+');
1850 }
1851 uval = sv->c.i;
1852 if (modifier == 'n') {
1853 val = -(int64_t)uval;
1854 cstr_printf(add_str, "%lld", (long long)val);
1855 } else if (uval > 0x7fffffffffffffffULL) {
1856 cstr_printf(add_str, "0x%llx", (unsigned long long)uval);
1857 } else {
1858 val = (int64_t)uval;
1859 cstr_printf(add_str, "%lld", (long long)val);
1860 }
1861 no_offset:;
1862 } else if ((r & VT_VALMASK) == VT_LOCAL) {
1863 cstr_printf(add_str, "[x29,#%d]", (int) sv->c.i);
1864 } else if (r & VT_LVAL) {
1865 reg = r & VT_VALMASK;
1866 if (reg >= VT_CONST)
1867 tcc_internal_error("");
1868 cstr_printf(add_str, "[x%d]", reg);
1869 } else {
1870 /* register case */
1871 reg = r & VT_VALMASK;
1872 if (reg >= VT_CONST)
1873 tcc_internal_error("");
1874
1875 if (ARM64_FREG_BASE <= reg && reg <= ARM64_FREG_LAST) {
1876 fp_reg = reg - ARM64_FREG_BASE;
1877 size = type_size(&sv->type, &align);
1878
1879 if (modifier == 0)
1880 modifier = size <= 4 ? 's'
1881 : size == 8 ? 'd'
1882 : 'q';
1883
1884 switch (modifier) {
1885 case 'b':
1886 case 'h':
1887 case 's':
1888 case 'd':
1889 case 'q':
1890 case 'Z':
1891 cstr_printf(add_str, "%c%d", modifier == 'Z' ? 'z' : modifier,
1892 fp_reg);
1893 return;
1894 default:
1895 tcc_error("invalid operand modifier for SIMD/FP register");
1896 return;
1897 }
1898 }
1899
1900 /* choose register operand size */
1901 if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
1902 (sv->type.t & VT_BTYPE) == VT_BOOL)
1903 size = 1;
1904 else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
1905 size = 2;
1906 else if ((sv->type.t & VT_BTYPE) == VT_LLONG ||
1907 (sv->type.t & VT_BTYPE) == VT_PTR)
1908 size = 8;
1909 else
1910 size = 4;
1911
1912 if (modifier == 'x') {
1913 size = 8;
1914 } else if (modifier == 'w' || modifier == 'k') {
1915 size = 4;
1916 } else if (modifier == 'b') {
1917 size = 1;
1918 } else if (modifier == 'h') {
1919 size = 2;
1920 } else if (modifier == 'q') {
1921 size = 8;
1922 }
1923
1924 if (size <= 4) {
1925 cstr_printf(add_str, "w%d", reg);
1926 } else {
1927 cstr_printf(add_str, "x%d", reg);
1928 }
1929 }
65}1930}
66 1931
67/* generate prolog and epilog code for asm statement */
68ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,1932ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
69 int nb_outputs, int is_output,1933 int nb_outputs, int is_output,
70 uint8_t *clobber_regs,1934 uint8_t *clobber_regs,
71 int out_reg)1935 int out_reg)
72{1936{
1937 uint8_t regs_allocated[NB_ASM_REGS];
1938 ASMOperand *op;
1939 int i, reg, saved_count, stack_size, stack_off;
1940 int saved_regs[12];
1941 static const uint8_t reg_saved[] = {
1942 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
1943 29, 30
1944 };
1945
1946 memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
1947 for (i = 0; i < nb_operands; i++) {
1948 op = &operands[i];
1949 if (op->reg >= 0)
1950 regs_allocated[op->reg] = 1;
1951 }
1952
1953 saved_count = 0;
1954 for (i = 0; i < sizeof(reg_saved) / sizeof(reg_saved[0]); i++) {
1955 reg = reg_saved[i];
1956 if (regs_allocated[reg])
1957 saved_regs[saved_count++] = reg;
1958 }
1959 stack_size = ((saved_count + 1) / 2) * 16;
1960
1961 if (!is_output) {
1962 if (saved_count > 0) {
1963 gen_sub_imm(31, 31, stack_size, 1, 0);
1964
1965 for (i = stack_off = 0; i < saved_count; ) {
1966 if (i + 1 < saved_count) {
1967 gen_ldst_pair(ARM64_STP_X, saved_regs[i], saved_regs[i + 1],
1968 TREG_SP, stack_off, 3);
1969 stack_off += 16;
1970 i += 2;
1971 } else {
1972 gen_ldst_imm(ARM64_STR_X, saved_regs[i], TREG_SP,
1973 stack_off, 3);
1974 i++;
1975 }
1976 }
1977 }
1978
1979 for (i = 0; i < nb_operands; i++) {
1980 op = &operands[i];
1981 if (op->reg >= 0) {
1982 if (op->is_memory) {
1983 arm64_load_memory_operand_base(op->reg, op->vt);
1984 } else if (i >= nb_outputs || op->is_rw) {
1985 load(op->reg, op->vt);
1986 }
1987 }
1988 }
1989 } else {
1990 for (i = 0; i < nb_outputs; i++) {
1991 op = &operands[i];
1992 if (op->reg >= 0) {
1993 if (op->is_memory)
1994 continue;
1995 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1996 if (!op->is_memory) {
1997 SValue sv;
1998 sv = *op->vt;
1999 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
2000 sv.type.t = VT_PTR;
2001 load(out_reg, &sv);
2002
2003 sv = *op->vt;
2004 sv.r = (sv.r & ~VT_VALMASK) | out_reg;
2005 store(op->reg, &sv);
2006 }
2007 } else {
2008 store(op->reg, op->vt);
2009 }
2010 }
2011 }
2012
2013 if (saved_count > 0) {
2014 for (i = stack_off = 0; i < saved_count; ) {
2015 if (i + 1 < saved_count) {
2016 gen_ldst_pair(ARM64_LDP_X, saved_regs[i], saved_regs[i + 1],
2017 TREG_SP, stack_off, 3);
2018 stack_off += 16;
2019 i += 2;
2020 } else {
2021 gen_ldst_imm(ARM64_LDR_X, saved_regs[i], TREG_SP,
2022 stack_off, 3);
2023 i++;
2024 }
2025 }
2026 gen_add_imm(31, 31, stack_size, 1, 0);
2027 }
2028 }
73}2029}
74 2030
75ST_FUNC void asm_compute_constraints(ASMOperand *operands,2031ST_FUNC void asm_compute_constraints(ASMOperand *operands,
@@ -77,17 +2033,247 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, · 1 unmodified line
77 const uint8_t *clobber_regs,2033 const uint8_t *clobber_regs,
78 int *pout_reg)2034 int *pout_reg)
79{2035{
2036 ASMOperand *op;
2037 int sorted_op[MAX_ASM_OPERANDS];
2038 int i, j, k, p1, p2, tmp, reg, c, reg_mask;
2039 const char *str;
2040 uint8_t regs_allocated[NB_ASM_REGS];
2041
2042 for (i = 0; i < nb_operands; i++) {
2043 op = &operands[i];
2044 op->input_index = -1;
2045 op->ref_index = -1;
2046 op->reg = -1;
2047 op->is_memory = 0;
2048 op->is_rw = 0;
2049 op->is_llong = 0;
2050 }
2051
2052 for (i = 0; i < nb_operands; i++) {
2053 op = &operands[i];
2054 str = op->constraint;
2055 str = skip_constraint_modifiers(str);
2056 if (isnum(*str) || *str == '[') {
2057 k = find_constraint(operands, nb_operands, str, NULL);
2058 if ((unsigned)k >= i || i < nb_outputs)
2059 tcc_error("invalid reference in constraint %d ('%s')", i, str);
2060 op->ref_index = k;
2061 if (operands[k].input_index >= 0)
2062 tcc_error("cannot reference twice the same operand");
2063 operands[k].input_index = i;
2064 op->priority = 5;
2065 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
2066 && op->vt->sym
2067 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
2068 op->priority = 1;
2069 op->reg = reg;
2070 } else {
2071 op->priority = constraint_priority(str);
2072 }
2073 }
2074
2075 for (i = 0; i < nb_operands; i++)
2076 sorted_op[i] = i;
2077 for (i = 0; i < nb_operands - 1; i++) {
2078 for (j = i + 1; j < nb_operands; j++) {
2079 p1 = operands[sorted_op[i]].priority;
2080 p2 = operands[sorted_op[j]].priority;
2081 if (p2 < p1) {
2082 tmp = sorted_op[i];
2083 sorted_op[i] = sorted_op[j];
2084 sorted_op[j] = tmp;
2085 }
2086 }
2087 }
2088
2089 for (i = 0; i < NB_ASM_REGS; i++) {
2090 if (clobber_regs[i])
2091 regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
2092 else
2093 regs_allocated[i] = 0;
2094 }
2095
2096 for (i = 0; i < nb_operands; i++) {
2097 j = sorted_op[i];
2098 op = &operands[j];
2099 str = op->constraint;
2100 if (op->ref_index >= 0)
2101 continue;
2102 if (op->input_index >= 0) {
2103 reg_mask = REG_IN_MASK | REG_OUT_MASK;
2104 } else if (j < nb_outputs) {
2105 reg_mask = REG_OUT_MASK;
2106 } else {
2107 reg_mask = REG_IN_MASK;
2108 }
2109 if (op->reg >= 0) {
2110 if (is_reg_allocated(op->reg))
2111 tcc_error("asm regvar requests register that's taken already");
2112 reg = op->reg;
2113 goto reg_found;
2114 }
2115 try_next:
2116 c = *str++;
2117 switch (c) {
2118 case '=':
2119 goto try_next;
2120 case '+':
2121 op->is_rw = 1;
2122 case '&':
2123 if (j >= nb_outputs)
2124 tcc_error("'%c' modifier can only be applied to outputs", c);
2125 reg_mask = REG_IN_MASK | REG_OUT_MASK;
2126 goto try_next;
2127 case 'r':
2128 for (reg = 0; reg < 31; reg++) {
2129 if (arm64_int_reg_is_allocatable(reg)
2130 && !is_reg_allocated(reg))
2131 goto reg_found;
2132 }
2133 goto try_next;
2134 case 'w':
2135 case 'f':
2136 for (reg = ARM64_FREG_BASE; reg <= ARM64_FREG_LAST; reg++) {
2137 if (!is_reg_allocated(reg))
2138 goto reg_found;
2139 }
2140 goto try_next;
2141 case 'x':
2142 case 'y':
2143 for (reg = ARM64_FREG_BASE; reg <= ARM64_FREG_LAST; reg++) {
2144 if (!is_reg_allocated(reg))
2145 goto reg_found;
2146 }
2147 goto try_next;
2148 case 'm':
2149 case 'g':
2150 if (j < nb_outputs || c == 'm') {
2151 if (!arm64_prepare_memory_operand(op, regs_allocated))
2152 goto try_next;
2153 }
2154 break;
2155 case 'Q':
2156 if (!arm64_memory_is_base_only(op->vt))
2157 goto try_next;
2158 if (!arm64_prepare_memory_operand(op, regs_allocated))
2159 goto try_next;
2160 break;
2161 case 'S':
2162 if ((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != (VT_CONST | VT_SYM))
2163 goto try_next;
2164 break;
2165 case 'U':
2166 if (str[0] != 'm' || str[1] != 'p')
2167 goto try_next;
2168 str += 2;
2169 if (!arm64_memory_is_pair_suitable(op->vt))
2170 goto try_next;
2171 if (!arm64_prepare_memory_operand(op, regs_allocated))
2172 goto try_next;
2173 break;
2174 case 'i':
2175 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
2176 goto try_next;
2177 break;
2178 case 'I':
2179 if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
2180 goto try_next;
2181 if (!is_valid_add_imm(op->vt->c.i))
2182 goto try_next;
2183 break;
2184 case 'J':
2185 if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
2186 goto try_next;
2187 if (!is_valid_add_imm(-op->vt->c.i))
2188 goto try_next;
2189 break;
2190 case 'K':
2191 if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
2192 goto try_next;
2193 if (!is_valid_logical_imm(op->vt->c.i, 32))
2194 goto try_next;
2195 break;
2196 case 'L':
2197 if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
2198 goto try_next;
2199 if (!is_valid_logical_imm(op->vt->c.i, 64))
2200 goto try_next;
2201 break;
2202 case 'M':
2203 case 'N':
2204 if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
2205 goto try_next;
2206 if (!is_valid_movw_imm(op->vt->c.i))
2207 goto try_next;
2208 break;
2209 case 'Z':
2210 if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
2211 goto try_next;
2212 if (op->vt->c.i != 0)
2213 goto try_next;
2214 break;
2215 case 'n':
2216 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
2217 goto try_next;
2218 break;
2219 default:
2220 tcc_error("asm constraint %d ('%s') could not be satisfied",
2221 j, op->constraint);
2222 break;
2223 }
2224 if (op->input_index >= 0) {
2225 operands[op->input_index].reg = op->reg;
2226 operands[op->input_index].is_llong = op->is_llong;
2227 }
2228 continue;
2229 reg_found:
2230 op->is_llong = 0;
2231 op->reg = reg;
2232 regs_allocated[reg] |= reg_mask;
2233 if (op->input_index >= 0) {
2234 operands[op->input_index].reg = op->reg;
2235 operands[op->input_index].is_llong = op->is_llong;
2236 }
2237 }
2238
2239 *pout_reg = -1;
2240 for (i = 0; i < nb_operands; i++) {
2241 op = &operands[i];
2242 if (op->reg >= 0 &&
2243 (op->vt->r & VT_VALMASK) == VT_LLOCAL &&
2244 !op->is_memory) {
2245 for (reg = 0; reg < 31; reg++) {
2246 if (!(regs_allocated[reg] & REG_OUT_MASK))
2247 goto reg_found2;
2248 }
2249 tcc_error("could not find free output register for reloading");
2250 reg_found2:
2251 *pout_reg = reg;
2252 break;
2253 }
2254 }
80}2255}
81 2256
2257/* Handle clobber list */
82ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)2258ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
83{2259{
84 asm_error();2260 int reg;
2261
2262 if (!strcmp(str, "memory") ||
2263 !strcmp(str, "cc") ||
2264 !strcmp(str, "flags"))
2265 return;
2266
2267 reg = arm64_parse_regvar(tok_alloc_const(str));
2268 if (reg == -1)
2269 tcc_error("invalid clobber register '%s'", str);
2270 clobber_regs[reg] = 1;
85}2271}
86 2272
87ST_FUNC int asm_parse_regvar (int t)2273/* Parse register variable - this is the ST_FUNC that tcc.h expects */
2274ST_FUNC int asm_parse_regvar(int t)
88{2275{
89 asm_error();2276 return arm64_parse_regvar(t);
90 return -1;
91}2277}
92 2278
93/*************************************************************/2279/*************************************************************/
arm64-tok.h+840−0
@@ -0,0 +1,840 @@
1/* ------------------------------------------------------------------ */
2/* ARM64 (AArch64) assembler token definitions for TCC */
3
4/* General purpose registers - 64-bit */
5 DEF_ASM(x0)
6 DEF_ASM(x1)
7 DEF_ASM(x2)
8 DEF_ASM(x3)
9 DEF_ASM(x4)
10 DEF_ASM(x5)
11 DEF_ASM(x6)
12 DEF_ASM(x7)
13 DEF_ASM(x8)
14 DEF_ASM(x9)
15 DEF_ASM(x10)
16 DEF_ASM(x11)
17 DEF_ASM(x12)
18 DEF_ASM(x13)
19 DEF_ASM(x14)
20 DEF_ASM(x15)
21 DEF_ASM(x16)
22 DEF_ASM(x17)
23 DEF_ASM(x18)
24 DEF_ASM(x19)
25 DEF_ASM(x20)
26 DEF_ASM(x21)
27 DEF_ASM(x22)
28 DEF_ASM(x23)
29 DEF_ASM(x24)
30 DEF_ASM(x25)
31 DEF_ASM(x26)
32 DEF_ASM(x27)
33 DEF_ASM(x28)
34 DEF_ASM(x29)
35 DEF_ASM(x30)
36
37/* General purpose registers - 32-bit */
38 DEF_ASM(w0)
39 DEF_ASM(w1)
40 DEF_ASM(w2)
41 DEF_ASM(w3)
42 DEF_ASM(w4)
43 DEF_ASM(w5)
44 DEF_ASM(w6)
45 DEF_ASM(w7)
46 DEF_ASM(w8)
47 DEF_ASM(w9)
48 DEF_ASM(w10)
49 DEF_ASM(w11)
50 DEF_ASM(w12)
51 DEF_ASM(w13)
52 DEF_ASM(w14)
53 DEF_ASM(w15)
54 DEF_ASM(w16)
55 DEF_ASM(w17)
56 DEF_ASM(w18)
57 DEF_ASM(w19)
58 DEF_ASM(w20)
59 DEF_ASM(w21)
60 DEF_ASM(w22)
61 DEF_ASM(w23)
62 DEF_ASM(w24)
63 DEF_ASM(w25)
64 DEF_ASM(w26)
65 DEF_ASM(w27)
66 DEF_ASM(w28)
67 DEF_ASM(w29)
68 DEF_ASM(w30)
69
70/* Special registers */
71 DEF_ASM(sp)
72 DEF_ASM(xzr)
73 DEF_ASM(wzr)
74
75/* SIMD/FP registers - 128-bit views */
76 DEF_ASM(v0)
77 DEF_ASM(v1)
78 DEF_ASM(v2)
79 DEF_ASM(v3)
80 DEF_ASM(v4)
81 DEF_ASM(v5)
82 DEF_ASM(v6)
83 DEF_ASM(v7)
84 DEF_ASM(v8)
85 DEF_ASM(v9)
86 DEF_ASM(v10)
87 DEF_ASM(v11)
88 DEF_ASM(v12)
89 DEF_ASM(v13)
90 DEF_ASM(v14)
91 DEF_ASM(v15)
92 DEF_ASM(v16)
93 DEF_ASM(v17)
94 DEF_ASM(v18)
95 DEF_ASM(v19)
96 DEF_ASM(v20)
97 DEF_ASM(v21)
98 DEF_ASM(v22)
99 DEF_ASM(v23)
100 DEF_ASM(v24)
101 DEF_ASM(v25)
102 DEF_ASM(v26)
103 DEF_ASM(v27)
104 DEF_ASM(v28)
105 DEF_ASM(v29)
106 DEF_ASM(v30)
107 DEF_ASM(v31)
108
109/* SIMD/FP registers - 64-bit views (double) */
110 DEF_ASM(d0)
111 DEF_ASM(d1)
112 DEF_ASM(d2)
113 DEF_ASM(d3)
114 DEF_ASM(d4)
115 DEF_ASM(d5)
116 DEF_ASM(d6)
117 DEF_ASM(d7)
118 DEF_ASM(d8)
119 DEF_ASM(d9)
120 DEF_ASM(d10)
121 DEF_ASM(d11)
122 DEF_ASM(d12)
123 DEF_ASM(d13)
124 DEF_ASM(d14)
125 DEF_ASM(d15)
126 DEF_ASM(d16)
127 DEF_ASM(d17)
128 DEF_ASM(d18)
129 DEF_ASM(d19)
130 DEF_ASM(d20)
131 DEF_ASM(d21)
132 DEF_ASM(d22)
133 DEF_ASM(d23)
134 DEF_ASM(d24)
135 DEF_ASM(d25)
136 DEF_ASM(d26)
137 DEF_ASM(d27)
138 DEF_ASM(d28)
139 DEF_ASM(d29)
140 DEF_ASM(d30)
141 DEF_ASM(d31)
142
143/* SIMD/FP registers - 32-bit views (single) */
144 DEF_ASM(s0)
145 DEF_ASM(s1)
146 DEF_ASM(s2)
147 DEF_ASM(s3)
148 DEF_ASM(s4)
149 DEF_ASM(s5)
150 DEF_ASM(s6)
151 DEF_ASM(s7)
152 DEF_ASM(s8)
153 DEF_ASM(s9)
154 DEF_ASM(s10)
155 DEF_ASM(s11)
156 DEF_ASM(s12)
157 DEF_ASM(s13)
158 DEF_ASM(s14)
159 DEF_ASM(s15)
160 DEF_ASM(s16)
161 DEF_ASM(s17)
162 DEF_ASM(s18)
163 DEF_ASM(s19)
164 DEF_ASM(s20)
165 DEF_ASM(s21)
166 DEF_ASM(s22)
167 DEF_ASM(s23)
168 DEF_ASM(s24)
169 DEF_ASM(s25)
170 DEF_ASM(s26)
171 DEF_ASM(s27)
172 DEF_ASM(s28)
173 DEF_ASM(s29)
174 DEF_ASM(s30)
175 DEF_ASM(s31)
176
177/* SIMD/FP registers - 16-bit views (half) */
178 DEF_ASM(h0)
179 DEF_ASM(h1)
180 DEF_ASM(h2)
181 DEF_ASM(h3)
182 DEF_ASM(h4)
183 DEF_ASM(h5)
184 DEF_ASM(h6)
185 DEF_ASM(h7)
186 DEF_ASM(h8)
187 DEF_ASM(h9)
188 DEF_ASM(h10)
189 DEF_ASM(h11)
190 DEF_ASM(h12)
191 DEF_ASM(h13)
192 DEF_ASM(h14)
193 DEF_ASM(h15)
194 DEF_ASM(h16)
195 DEF_ASM(h17)
196 DEF_ASM(h18)
197 DEF_ASM(h19)
198 DEF_ASM(h20)
199 DEF_ASM(h21)
200 DEF_ASM(h22)
201 DEF_ASM(h23)
202 DEF_ASM(h24)
203 DEF_ASM(h25)
204 DEF_ASM(h26)
205 DEF_ASM(h27)
206 DEF_ASM(h28)
207 DEF_ASM(h29)
208 DEF_ASM(h30)
209 DEF_ASM(h31)
210
211/* SIMD/FP registers - 8-bit views (byte) */
212 DEF_ASM(b0)
213 DEF_ASM(b1)
214 DEF_ASM(b2)
215 DEF_ASM(b3)
216 DEF_ASM(b4)
217 DEF_ASM(b5)
218 DEF_ASM(b6)
219 DEF_ASM(b7)
220 DEF_ASM(b8)
221 DEF_ASM(b9)
222 DEF_ASM(b10)
223 DEF_ASM(b11)
224 DEF_ASM(b12)
225 DEF_ASM(b13)
226 DEF_ASM(b14)
227 DEF_ASM(b15)
228 DEF_ASM(b16)
229 DEF_ASM(b17)
230 DEF_ASM(b18)
231 DEF_ASM(b19)
232 DEF_ASM(b20)
233 DEF_ASM(b21)
234 DEF_ASM(b22)
235 DEF_ASM(b23)
236 DEF_ASM(b24)
237 DEF_ASM(b25)
238 DEF_ASM(b26)
239 DEF_ASM(b27)
240 DEF_ASM(b28)
241 DEF_ASM(b29)
242 DEF_ASM(b30)
243 DEF_ASM(b31)
244
245/* Condition codes */
246 DEF_ASM(eq)
247 DEF_ASM(ne)
248 DEF_ASM(cs)
249 DEF_ASM(hs)
250 DEF_ASM(cc)
251 DEF_ASM(lo)
252 DEF_ASM(mi)
253 DEF_ASM(pl)
254 DEF_ASM(vs)
255 DEF_ASM(vc)
256 DEF_ASM(hi)
257 DEF_ASM(ls)
258 DEF_ASM(ge)
259 DEF_ASM(lt)
260 DEF_ASM(gt)
261 DEF_ASM(le)
262 DEF_ASM(al)
263
264/* Data processing - arithmetic (no condition suffixes for ARM64) */
265 DEF_ASM(add)
266 DEF_ASM(adds)
267 DEF_ASM(sub)
268 DEF_ASM(subs)
269 DEF_ASM(cmn)
270 DEF_ASM(cmp)
271 DEF_ASM(neg)
272 DEF_ASM(negs)
273 DEF_ASM(adc)
274 DEF_ASM(adcs)
275 DEF_ASM(sbc)
276 DEF_ASM(sbcs)
277 DEF_ASM(ngc)
278 DEF_ASM(ngcs)
279
280/* Data processing - bitwise */
281 DEF_ASM(and)
282 DEF_ASM(ands)
283 DEF_ASM(bic)
284 DEF_ASM(bics)
285 DEF_ASM(orr)
286 DEF_ASM(orn)
287 DEF_ASM(eor)
288 DEF_ASM(eon)
289 DEF_ASM(mvn)
290 DEF_ASM(mov)
291
292/* Shifts */
293 DEF_ASM(lsl)
294 DEF_ASM(lsr)
295 DEF_ASM(asr)
296 DEF_ASM(ror)
297
298/* Multiply/divide */
299 DEF_ASM(mul)
300 DEF_ASM(madd)
301 DEF_ASM(msub)
302 DEF_ASM(smaddl)
303 DEF_ASM(smsubl)
304 DEF_ASM(umaddl)
305 DEF_ASM(umsubl)
306 DEF_ASM(smulh)
307 DEF_ASM(umulh)
308 DEF_ASM(udiv)
309 DEF_ASM(sdiv)
310
311/* Moves */
312 DEF_ASM(movz)
313 DEF_ASM(movn)
314 DEF_ASM(movk)
315
316/* Compare/test */
317 DEF_ASM(tst)
318 DEF_ASM(teq)
319
320/* Branch instructions */
321 DEF_ASM(b)
322 DEF_ASM(bl)
323 DEF_ASM(br)
324 DEF_ASM(blr)
325 DEF_ASM(ret)
326 DEF_ASM(cbz)
327 DEF_ASM(cbnz)
328 DEF_ASM(tbz)
329 DEF_ASM(tbnz)
330
331/* Conditional branches */
332 DEF_ASM(beq)
333 DEF_ASM(bne)
334 DEF_ASM(bcs)
335 DEF_ASM(bhs)
336 DEF_ASM(bcc)
337 DEF_ASM(blo)
338 DEF_ASM(bmi)
339 DEF_ASM(bpl)
340 DEF_ASM(bvs)
341 DEF_ASM(bvc)
342 DEF_ASM(bhi)
343 DEF_ASM(bls)
344 DEF_ASM(bge)
345 DEF_ASM(blt)
346 DEF_ASM(bgt)
347 DEF_ASM(ble)
348
349/* Conditional select */
350 DEF_ASM(csel)
351 DEF_ASM(csinc)
352 DEF_ASM(csinv)
353 DEF_ASM(csneg)
354
355/* Load/Store */
356 DEF_ASM(ldr)
357 DEF_ASM(ldrb)
358 DEF_ASM(ldrh)
359 DEF_ASM(ldrsb)
360 DEF_ASM(ldrsh)
361 DEF_ASM(ldrsw)
362 DEF_ASM(str)
363 DEF_ASM(strb)
364 DEF_ASM(strh)
365
366/* Load/Store - pair */
367 DEF_ASM(ldp)
368 DEF_ASM(stp)
369 DEF_ASM(ldpsw)
370
371/* Address generation */
372 DEF_ASM(adr)
373 DEF_ASM(adrp)
374
375/* System instructions */
376 DEF_ASM(mrs)
377 DEF_ASM(msr)
378 DEF_ASM(nop)
379 DEF_ASM(wfi)
380 DEF_ASM(wfe)
381 DEF_ASM(sev)
382 DEF_ASM(sevl)
383 DEF_ASM(isb)
384 DEF_ASM(dsb)
385 DEF_ASM(dmb)
386
387/* Hints */
388 DEF_ASM(yield)
389 DEF_ASM(clrex)
390
391/* Push/pop */
392 DEF_ASM(push)
393 DEF_ASM(pop)
394
395/* Floating point */
396 DEF_ASM(fmov)
397 DEF_ASM(fadd)
398 DEF_ASM(fsub)
399 DEF_ASM(fmul)
400 DEF_ASM(fnmul)
401 DEF_ASM(fdiv)
402 DEF_ASM(fmax)
403 DEF_ASM(fmin)
404 DEF_ASM(fmaxnm)
405 DEF_ASM(fminnm)
406 DEF_ASM(fsqrt)
407 DEF_ASM(fabs)
408 DEF_ASM(fneg)
409 DEF_ASM(frintn)
410 DEF_ASM(frintp)
411 DEF_ASM(frintm)
412 DEF_ASM(frintz)
413 DEF_ASM(frinta)
414 DEF_ASM(frintx)
415 DEF_ASM(frinti)
416 DEF_ASM(fcmp)
417 DEF_ASM(fcmpe)
418 DEF_ASM(fccmp)
419 DEF_ASM(fccmpe)
420 DEF_ASM(fcvts)
421 DEF_ASM(fcvtd)
422 DEF_ASM(fcvth)
423 DEF_ASM(fcvtx)
424 DEF_ASM(scvtf)
425 DEF_ASM(ucvtf)
426 DEF_ASM(fcvtns)
427 DEF_ASM(fcvtnu)
428 DEF_ASM(fcvtps)
429 DEF_ASM(fcvtpu)
430
431/* SIMD instructions */
432 DEF_ASM(addv)
433 DEF_ASM(faddp)
434 DEF_ASM(fmaxp)
435 DEF_ASM(fminp)
436 DEF_ASM(fmaxnmp)
437 DEF_ASM(fminnmp)
438 DEF_ASM(addp)
439 DEF_ASM(bif)
440 DEF_ASM(bit)
441 DEF_ASM(bsl)
442 DEF_ASM(dup)
443 DEF_ASM(ext)
444 DEF_ASM(ins)
445 DEF_ASM(movi)
446 DEF_ASM(mvni)
447 DEF_ASM(not)
448 DEF_ASM(shl)
449 DEF_ASM(shll)
450 DEF_ASM(shll2)
451 DEF_ASM(sli)
452 DEF_ASM(sri)
453 DEF_ASM(sqshl)
454 DEF_ASM(sqshlu)
455 DEF_ASM(srshl)
456 DEF_ASM(sshll)
457 DEF_ASM(sshll2)
458 DEF_ASM(sshr)
459 DEF_ASM(ushll)
460 DEF_ASM(ushll2)
461 DEF_ASM(ushr)
462
463/* Misc */
464 DEF_ASM(bfm)
465 DEF_ASM(sbfm)
466 DEF_ASM(ubfm)
467 DEF_ASM(extr)
468 DEF_ASM(crc32b)
469 DEF_ASM(crc32h)
470 DEF_ASM(crc32w)
471 DEF_ASM(crc32x)
472 DEF_ASM(crc32cb)
473 DEF_ASM(crc32ch)
474 DEF_ASM(crc32cw)
475 DEF_ASM(crc32cx)
476 DEF_ASM(rev)
477 DEF_ASM(rev16)
478 DEF_ASM(rev32)
479 DEF_ASM(rev64)
480 DEF_ASM(clz)
481 DEF_ASM(cls)
482 DEF_ASM(rbit)
483
484/* Exception generating */
485 DEF_ASM(svc)
486 DEF_ASM(hvc)
487 DEF_ASM(smc)
488 DEF_ASM(brk)
489 DEF_ASM(hlt)
490 DEF_ASM(dcps1)
491 DEF_ASM(dcps2)
492 DEF_ASM(dcps3)
493
494/* Conditional branches */
495 DEF_ASM(b_eq)
496 DEF_ASM(b_ne)
497 DEF_ASM(b_cs)
498 DEF_ASM(b_cc)
499 DEF_ASM(b_mi)
500 DEF_ASM(b_pl)
501 DEF_ASM(b_vs)
502 DEF_ASM(b_vc)
503 DEF_ASM(b_hi)
504 DEF_ASM(b_ls)
505 DEF_ASM(b_ge)
506 DEF_ASM(b_lt)
507 DEF_ASM(b_gt)
508 DEF_ASM(b_le)
509
510/* LD/ST exclusive */
511 DEF_ASM(ldxr)
512 DEF_ASM(ldxrb)
513 DEF_ASM(ldxrh)
514 DEF_ASM(stxr)
515 DEF_ASM(stxrb)
516 DEF_ASM(stxrh)
517 DEF_ASM(ldaxr)
518 DEF_ASM(ldaxrb)
519 DEF_ASM(ldaxrh)
520 DEF_ASM(stlxr)
521 DEF_ASM(stlxrb)
522 DEF_ASM(stlxrh)
523
524/* LD/ST acquire-release */
525 DEF_ASM(ldar)
526 DEF_ASM(ldarb)
527 DEF_ASM(ldarh)
528 DEF_ASM(stlr)
529 DEF_ASM(stlrb)
530 DEF_ASM(stlrh)
531 DEF_ASM(ldalr)
532 DEF_ASM(ldalrb)
533 DEF_ASM(ldalrh)
534 DEF_ASM(stllr)
535 DEF_ASM(stllrb)
536 DEF_ASM(stllrh)
537
538/* LD/ST unscaled immediate */
539 DEF_ASM(ldur)
540 DEF_ASM(ldurb)
541 DEF_ASM(ldurh)
542 DEF_ASM(ldursb)
543 DEF_ASM(ldursh)
544 DEF_ASM(ldursw)
545 DEF_ASM(stur)
546 DEF_ASM(sturb)
547 DEF_ASM(sturh)
548
549/* Vector load/store */
550 DEF_ASM(ld1)
551 DEF_ASM(st1)
552 DEF_ASM(ld2)
553 DEF_ASM(st2)
554 DEF_ASM(ld3)
555 DEF_ASM(st3)
556 DEF_ASM(ld4)
557 DEF_ASM(st4)
558
559/* ------------------------------------------------------------------ */
560/* ARM64 instruction opcode constants and encoding helpers */
561/* ------------------------------------------------------------------ */
562
563/* Data processing - immediate */
564#define ARM64_ADD_IMM 0x11000000U
565#define ARM64_ADDS_IMM 0x2B000000U
566#define ARM64_SUB_IMM 0x51000000U
567#define ARM64_SUBS_IMM 0x6B000000U
568
569/* Data processing - register */
570#define ARM64_ADD_REG 0x0B000000U
571#define ARM64_ADDS_REG 0x2B000000U
572#define ARM64_SUB_REG 0x4B000000U
573#define ARM64_SUBS_REG 0x6B000000U
574#define ARM64_AND_REG 0x0A000000U
575#define ARM64_ANDS_REG 0x6A000000U
576#define ARM64_ORR_REG 0x2A000000U
577#define ARM64_EOR_REG 0x4A000000U
578#define ARM64_MUL_REG 0x1B000000U /* Base opcode, Rm/Rn/Rd must be filled in */
579
580/* Move wide immediate */
581#define ARM64_MOVZ 0x52800000U
582#define ARM64_MOVN 0x12800000U
583#define ARM64_MOVK 0xF2800000U
584/* ARM64_MOVI_W/X removed: MOVI is a SIMD&FP instruction, not general-purpose */
585/* Use MOVZ/MOVN/MOVK for general-purpose, or SIMD MOVI variants (0x0F000400, etc.) */
586
587/* MOVZ/MOVN 64-bit base opcodes */
588#define ARM64_MOVZ64 0xD2800000U /* MOVZ (64-bit), use with ARM64_HW() */
589#define ARM64_MOVN64 0x92800000U /* MOVN (64-bit), use with ARM64_HW() */
590
591/* Move wide immediate shift field (LSL #0/16/32/48 encoded as hw*16) */
592#define ARM64_HW(v) (((uint32_t)(v) & 3) << 21)
593
594/* Load/store register (unsigned immediate) */
595#define ARM64_LDR_X 0xF9400000U
596#define ARM64_LDR_W 0xB9400000U
597#define ARM64_LDR_B 0x39400000U
598#define ARM64_LDR_H 0x79400000U
599#define ARM64_LDR_D 0xFD400000U
600#define ARM64_LDR_S 0xBD400000U
601#define ARM64_STR_X 0xF9000000U
602#define ARM64_STR_W 0xB9000000U
603#define ARM64_STR_B 0x39000000U
604#define ARM64_STR_H 0x79000000U
605#define ARM64_STR_D 0xFD000000U
606#define ARM64_STR_S 0xBD000000U
607
608/* Load/store register (unscaled immediate) */
609#define ARM64_LDUR_X 0xF8400000U
610#define ARM64_LDUR_W 0xB8400000U
611#define ARM64_LDUR_B 0x38400000U
612#define ARM64_LDUR_H 0x78400000U
613#define ARM64_STUR_X 0xF8000000U
614#define ARM64_STUR_W 0xB8000000U
615#define ARM64_STUR_B 0x38000000U
616#define ARM64_STUR_H 0x78000000U
617
618/* Load/store register (register offset) */
619#define ARM64_LDR_X_REG 0xF8606800U
620#define ARM64_LDR_W_REG 0xB8606800U
621#define ARM64_LDR_B_REG 0x38606800U
622#define ARM64_LDR_H_REG 0x78606800U
623#define ARM64_STR_X_REG 0xF8206800U
624#define ARM64_STR_W_REG 0xB8206800U
625#define ARM64_STR_B_REG 0x38206800U
626#define ARM64_STR_H_REG 0x78206800U
627
628/* Load/store (pre/post-indexed) */
629#define ARM64_STR_X_PRE 0xF8000000U /* STR X pre-indexed base */
630#define ARM64_LDR_X_POST 0xF8400000U /* LDR X post-indexed base */
631
632/* SIMD load/store (unsigned immediate) */
633#define ARM64_LDR_SCALAR 0x3D400000U /* Base for scalar load (size built dynamically) */
634#define ARM64_LDR_S_VEC 0xBD400000U
635#define ARM64_LDR_D_VEC 0xFD400000U
636#define ARM64_LDR_Q_VEC 0x3DC00000U
637#define ARM64_STR_SCALAR 0x3D000000U /* Base for scalar store (size built dynamically) */
638#define ARM64_STR_S_VEC 0xBD000000U
639#define ARM64_STR_D_VEC 0xFD000000U
640#define ARM64_STR_Q_VEC 0x3D800000U
641
642/* SIMD load/store (unscaled immediate) */
643#define ARM64_LDUR_S_SIMD 0xBC400000U
644#define ARM64_LDUR_D_SIMD 0xFC400000U
645#define ARM64_LDUR_Q_SIMD 0x3C400000U
646#define ARM64_STUR_S_SIMD 0xBC000000U
647#define ARM64_STUR_D_SIMD 0xFC000000U
648#define ARM64_STUR_Q_SIMD 0x3C000000U
649
650/* SIMD load/store (register offset) */
651#define ARM64_LDR_S_REG 0xBC606800U
652#define ARM64_LDR_D_REG 0xFC606800U
653#define ARM64_LDR_Q_REG 0x3C606800U
654#define ARM64_STR_S_REG 0xBC206800U
655#define ARM64_STR_D_REG 0xFC206800U
656#define ARM64_STR_Q_REG 0x3C206800U
657
658/* Load/store pair */
659#define ARM64_LDP_X 0xA9400000U
660#define ARM64_LDP_X_PRE 0xA9C00000U
661#define ARM64_LDP_X_POST 0xA8C00000U
662#define ARM64_STP_X 0xA9000000U
663#define ARM64_STP_X_PRE 0xA9800000U
664#define ARM64_STP_X_POST 0xA8800000U
665#define ARM64_LDP_D 0x6D400000U
666#define ARM64_LDP_D_PRE 0x6DC00000U
667#define ARM64_LDP_D_POST 0x6CC00000U
668#define ARM64_STP_D 0x6D000000U
669#define ARM64_STP_D_PRE 0x6D800000U
670#define ARM64_STP_D_POST 0x6C800000U
671
672/* Branch instructions */
673#define ARM64_B 0x14000000U
674#define ARM64_BL 0x94000000U
675#define ARM64_BR 0xD61F0000U
676#define ARM64_BLR 0xD63F0000U
677#define ARM64_RET 0xD65F0000U
678
679/* Conditional branch */
680#define ARM64_B_COND 0x54000000U
681
682/* Compare and branch */
683#define ARM64_CBZ 0x34000000U
684#define ARM64_CBNZ 0x35000000U
685
686/* System instructions */
687#define ARM64_NOP 0xD503201FU
688#define ARM64_ISB 0xD50330DFU
689#define ARM64_DSB 0xD503309FU
690#define ARM64_DMB 0xD50330BFU
691#define ARM64_MRS 0xD5380000U
692#define ARM64_MSR 0xD5180000U
693#define ARM64_MRS_FPCR 0xD53B4400U
694#define ARM64_MRS_FPSR 0xD53B4420U
695#define ARM64_MSR_FPCR 0xD51B4400U
696#define ARM64_MSR_FPSR 0xD51B4420U
697
698/* Shifts (register) */
699#define ARM64_LSL_REG 0x1AC02000U
700#define ARM64_LSR_REG 0x1AC02400U
701#define ARM64_ASR_REG 0x1AC02800U
702#define ARM64_ROR_REG 0x1AC02C00U
703
704/* Shifts (immediate - UBFM/SBFM) */
705#define ARM64_LSL_IMM 0xD3400000U
706#define ARM64_LSR_IMM 0xD3400000U
707#define ARM64_LSR_IMM_32 0x53000000U /* 32-bit LSR base */
708#define ARM64_ASR_IMM 0x93400000U
709
710/* Shifted register encoding for ORR/AND/EOR */
711#define ARM64_SHIFT_LSL(imm) (((uint32_t)(imm) & 63) << 10)
712#define ARM64_SHIFT_LSR(imm) (0x00200000U | (((uint32_t)(imm) & 63) << 10))
713#define ARM64_SHIFT_ASR(imm) (0x00400000U | (((uint32_t)(imm) & 63) << 10))
714#define ARM64_SHIFT_ROR(imm) (0x00600000U | (((uint32_t)(imm) & 63) << 10))
715
716/* UBFM/SBFM immediate fields (for LSL/LSR/ASR immediate aliases) */
717#define ARM64_IMM_R(r) (((uint32_t)(r) & 0x3F) << 16)
718#define ARM64_IMM_S(s) (((uint32_t)(s) & 0x3F) << 10)
719
720/* Extended register encoding */
721#define ARM64_EXTEND_LSL(lsl) (((uint32_t)(lsl) & 7) << 10)
722
723/* MOV (register) - ORR with zero register */
724#define ARM64_MOV_REG 0x2A0003E0U
725
726/* Address generation */
727#define ARM64_ADRP 0x90000000U
728#define ARM64_ADR 0x10000000U
729
730/* Logical immediate */
731#define ARM64_AND_IMM 0x12000000U
732#define ARM64_ORR_IMM_BASE 0x32000000U
733#define ARM64_EOR_IMM 0x52000000U
734#define ARM64_ANDS_IMM 0x72000000U
735#define ARM64_ORR_IMM 0x320003E0U /* ORR immediate alias with Rn = XZR/WZR */
736
737/* ------------------------------------------------------------------ */
738/* ARM64 instruction encoding helper macros */
739/* ------------------------------------------------------------------ */
740
741/* Register field encodings */
742#define ARM64_RD(r) ((uint32_t)(r) & 0x1FU)
743#define ARM64_RN(r) (((uint32_t)(r) & 0x1FU) << 5)
744#define ARM64_RM(r) (((uint32_t)(r) & 0x1FU) << 16)
745#define ARM64_RT(r) ((uint32_t)(r) & 0x1FU)
746#define ARM64_RT2(r) (((uint32_t)(r) & 0x1FU) << 10)
747
748/* Immediate field encodings */
749#define ARM64_IMM12(v) (((uint32_t)(v) & 0xFFFU) << 10)
750#define ARM64_IMM7(v) (((uint32_t)(v) & 0x7FU) << 15)
751#define ARM64_IMM14(v) (((uint32_t)(v) & 0x3FFFU) << 5)
752#define ARM64_IMM16(v) (((uint32_t)(v) & 0xFFFFU) << 5)
753#define ARM64_IMM_HW(v, hw) (((uint32_t)(v) & 0xFFFFU) << 5 | (((hw) & 3) << 21))
754
755/* Shift and size encodings */
756#define ARM64_SIZE(s) (((uint32_t)(s) & 3) << 30)
757#define ARM64_SF(s) (((uint32_t)(s) & 1) << 31)
758#define ARM64_S(v) (((uint32_t)(v) & 1) << 29)
759#define ARM64_N(v) (((uint32_t)(v) & 1) << 22)
760#define ARM64_SH(v) (((uint32_t)(v) & 1) << 22)
761
762/* Condition code encoding */
763#define ARM64_COND(c) ((uint32_t)(c) & 0xFU)
764
765/* Branch offset encoding */
766#define ARM64_OFFSET26(v) (((uint32_t)(v) >> 2) & 0x3FFFFFFU)
767#define ARM64_OFFSET19(v) (((uint32_t)(v) >> 2) & 0x7FFFFU)
768#define ARM64_OFFSET14(v) (((uint32_t)(v) >> 2) & 0x3FFFU)
769
770/* Special register field (for MRS/MSR) */
771#undef ARM64_SYSREG
772#define ARM64_SYSREG(op0, op1, crn, crm, op2) \
773 ((((op0) & 3) << 19) | (((op1) & 7) << 16) | \
774 (((crn) & 15) << 12) | (((crm) & 15) << 8) | (((op2) & 7) << 5))
775
776/* Barrier option encoding */
777#define ARM64_ISB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
778#define ARM64_DSB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
779#define ARM64_DMB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
780
781/* Additional opcodes for code generator - VERIFIED */
782/* Note: Many of these are specific instances, not general templates */
783
784/* Floating-point move - VERIFIED */
785#define ARM64_FMOV_D_S 0x1E604000U /* FMOV Dd,Dn (scalar) */
786#define ARM64_FMOV_X_D 0x9E660000U /* FMOV Xd,Dn (general to FP) */
787#define ARM64_FMOV_W_S 0x1E260000U /* FMOV Wd,Sn (general to FP) */
788/* ARM64_FMOV_S_D removed: 0x4EA01C00 is SIMD vector, not scalar FMOV */
789/* Use 0x1E204000 for FMOV Sd,Sn or 0x1E604000 variant for cross-size */
790
791/* FMOV variants for code generator */
792#define ARM64_FMOV_SCALAR 0x1E604000U /* FMOV Dd, Dn (scalar FP) */
793#define ARM64_FMOV_XD 0x9E660000U /* FMOV Xd, Dn (FP to GP 64-bit) */
794#define ARM64_FMOV_WS 0x1E260000U /* FMOV Wd, Sn (FP to GP 32-bit) */
795
796/* MOV vector (ORR vector register alias) */
797#define ARM64_MOV_V16B 0x4EA01C00U /* MOV Vd.16B, Vn.16B (ORR vector, Rm=Rn alias) */
798
799/* Load/Store SIMD&FP - Base opcodes (register fields must be filled in) */
800#define ARM64_STR_Q_PRE 0x3C800000U /* STR Q pre-index base */
801#define ARM64_LDR_Q_POST 0x3CC00000U /* LDR Q post-index base */
802
803/* LDPSW - Base opcode (register fields must be filled in) */
804/* Use gen_ldst_pair() with appropriate mode for LDPSW */
805/* Base encodings: 0x68C00000 (post), 0x69400000 (offset), 0x69C00000 (pre) */
806
807/* ARM64_LDR_S_SIMD removed: 0x0D00801C is not a standard encoding */
808/* Use ARM64_LDR_S (0xBD400000) for scalar S or ARM64_LDR_S_VEC for SIMD */
809
810/* MOV between SIMD and general - Use UMOV/SMOV instead */
811/* ARM64_MOV_V_D removed: 0x4E083C00 is UMOV/SMOV encoding */
812/* Use appropriate UMOV/SMOV base: 0x0E002C00/0x0E003C00 (32-bit) */
813/* or 0x4E002C00/0x4E003C00 (64-bit) */
814
815/* Verified from previous section */
816#define ARM64_FCMP 0x1E202008U /* FCMP with zero */
817#define ARM64_SDIV 0x1AC00C00U /* SDIV (32-bit) */
818
819/* EXTR (Extract) */
820#define ARM64_EXTR 0x13800000U /* EXTR Wd, Wn, Wm, #imm (32-bit) */
821#define ARM64_EXTR64 0x93C00000U /* EXTR Xd, Xn, Xm, #imm (64-bit) */
822
823/* ARM64_MUL removed - use ARM64_MUL_REG with gen_dp_reg() */
824
825/* ORR shifted - Base opcodes (register fields must be filled in) */
826#define ARM64_ORR_REG_LSL 0x2A000000U /* ORR (shifted register) base */
827/* ARM64_ORR_REG_LSL32 removed: use ARM64_ORR_REG_LSL with SF=1 */
828/* ARM64_ORR_REG_MOV is duplicate of ARM64_MOV_REG */
829
830/* LSR immediate - These are UBFM encodings, use gen_shift() instead */
831/* Base UBFM encodings: 0x53000000 (W), 0xD3400000 (X) */
832/* gen_shift() handles immr/imms encoding for LSR/LSL/ASR */
833/* ARM64_LSR_W_8, ARM64_LSR_X_8, ARM64_LSR_X_16, ARM64_LSR_X_24 removed */
834/* They are specific instances, not templates */
835
836/* SUB shifted - Base opcode (use gen_sub_reg or asm handler) */
837#define ARM64_SUB_REG_LSL 0xCB000000U /* SUB (shifted register) base */
838
839/* Duplicates removed: ARM64_LDP_X, ARM64_B, ARM64_BL, ARM64_BR, ARM64_NOP */
840/* These are already defined in their respective sections above */
tccasm.c+14−3
@@ -1032,11 +1032,14 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) · 1031 unmodified lines
1032 tcc_debug_line(s1);1032 tcc_debug_line(s1);
1033 parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */1033 parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
1034 redo:1034 redo:
1035#if !defined(TCC_TARGET_ARM64)
1035 if (tok == '#') {1036 if (tok == '#') {
1036 /* horrible gas comment */1037 /* horrible gas comment */
1037 while (tok != TOK_LINEFEED)1038 while (tok != TOK_LINEFEED)
1038 next();1039 next();
1039 } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {1040 } else
1041#endif
1042 if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
1040 asm_parse_directive(s1, global);1043 asm_parse_directive(s1, global);
1041 } else if (tok == TOK_PPNUM) {1044 } else if (tok == TOK_PPNUM) {
1042 const char *p;1045 const char *p;
@@ -1176,6 +1179,9 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 133 unmodified lines
1176 if (*str == 'c' || *str == 'n' ||1179 if (*str == 'c' || *str == 'n' ||
1177 *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||1180 *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
1178 *str == 'q' || *str == 'l' ||1181 *str == 'q' || *str == 'l' ||
1182#ifdef TCC_TARGET_ARM64
1183 *str == 'x' || *str == 's' || *str == 'd' || *str == 'Z' ||
1184#endif
1179#ifdef TCC_TARGET_RISCV641185#ifdef TCC_TARGET_RISCV64
1180 *str == 'z' ||1186 *str == 'z' ||
1181#endif1187#endif
@@ -1196,7 +1202,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 14 unmodified lines
1196 sv = *op->vt;1202 sv = *op->vt;
1197 if (op->reg >= 0) {1203 if (op->reg >= 0) {
1198 sv.r = op->reg;1204 sv.r = op->reg;
1199 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)1205 if (op->is_memory)
1200 sv.r |= VT_LVAL;1206 sv.r |= VT_LVAL;
1201 }1207 }
1202 subst_asm_operand(out_str, &sv, modifier);1208 subst_asm_operand(out_str, &sv, modifier);
@@ -1248,7 +1254,12 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr, · 45 unmodified lines
1248 if ((vtop->r & VT_LVAL) &&1254 if ((vtop->r & VT_LVAL) &&
1249 ((vtop->r & VT_VALMASK) == VT_LLOCAL ||1255 ((vtop->r & VT_VALMASK) == VT_LLOCAL ||
1250 (vtop->r & VT_VALMASK) < VT_CONST) &&1256 (vtop->r & VT_VALMASK) < VT_CONST) &&
1251 !strchr(op->constraint, 'm')) {1257 !strchr(op->constraint, 'm')
1258#ifdef TCC_TARGET_ARM64
1259 && !strchr(op->constraint, 'Q')
1260 && !strstr(op->constraint, "Ump")
1261#endif
1262 ) {
1252 gv(RC_INT);1263 gv(RC_INT);
1253 }1264 }
1254 }1265 }
tccpp.c+3−3
@@ -942,11 +942,11 @@ redo_start: · 941 unmodified lines
942 else if (parse_flags & PARSE_FLAG_ASM_FILE)942 else if (parse_flags & PARSE_FLAG_ASM_FILE)
943 p = parse_line_comment(p - 1);943 p = parse_line_comment(p - 1);
944 }944 }
945#if !defined(TCC_TARGET_ARM)945#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
946 else if (parse_flags & PARSE_FLAG_ASM_FILE)946 else if (parse_flags & PARSE_FLAG_ASM_FILE)
947 p = parse_line_comment(p - 1);947 p = parse_line_comment(p - 1);
948#else948#else
949 /* ARM assembly uses '#' for constants */949 /* ARM/ARM64 assembly uses '#' for constants */
950#endif950#endif
951 break;951 break;
952_default:952_default:
@@ -2678,7 +2678,7 @@ maybe_newline: · 1725 unmodified lines
2678 p++;2678 p++;
2679 tok = TOK_TWOSHARPS;2679 tok = TOK_TWOSHARPS;
2680 } else {2680 } else {
2681#if !defined(TCC_TARGET_ARM)2681#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
2682 if (parse_flags & PARSE_FLAG_ASM_FILE) {2682 if (parse_flags & PARSE_FLAG_ASM_FILE) {
2683 p = parse_line_comment(p - 1);2683 p = parse_line_comment(p - 1);
2684 goto redo_no_start;2684 goto redo_no_start;
tcctok.h+5−1
@@ -421,10 +421,14 @@ · 420 unmodified lines
421#include "i386-tok.h"421#include "i386-tok.h"
422#endif422#endif
423 423
424#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64424#if defined TCC_TARGET_ARM
425#include "arm-tok.h"425#include "arm-tok.h"
426#endif426#endif
427 427
428#if defined TCC_TARGET_ARM64
429#include "arm64-tok.h"
430#endif
431
428#if defined TCC_TARGET_RISCV64432#if defined TCC_TARGET_RISCV64
429#include "riscv64-tok.h"433#include "riscv64-tok.h"
430#endif434#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t