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 @@
11 /*************************************************************/
22 /*
3− * ARM64 dummy assembler for TCC
3+ * ARM64 (AArch64) assembler for TCC
44 *
5+ * Based on ARM64 Architecture Reference Manual
6+ * Supports AArch64 assembler parsing and extended inline asm
7+ * with operands, constraints, and clobbers.
58 */
69
710 #ifdef TARGET_DEFS_ONLY
811
912 #define CONFIG_TCC_ASM
10−#define NB_ASM_REGS 16
13+/* 32 general purpose + 32 SIMD/FP registers */
14+#define NB_ASM_REGS 64
1115
1216 ST_FUNC void g(int c);
1317 ST_FUNC void gen_le16(int c);
@@ -16,13 +20,98 @@ ST_FUNC void gen_le32(int c); · 2 unmodified lines
1620 /*************************************************************/
1721 #else
1822 /*************************************************************/
23+
1924 #define USING_GLOBALS
2025 #include "tcc.h"
2126
22−static void asm_error(void)
23−{
24− tcc_error("ARM asm not implemented.");
25−}
27+/* Register type flags */
28+#define REG_X 0x01 /* 64-bit general purpose */
29+#define REG_W 0x02 /* 32-bit general purpose */
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 */
37+enum {
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+
96+typedef 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+
107+enum {
108+ ADDR_OFF,
109+ ADDR_PRE,
110+ ADDR_POST,
111+};
112+
113+/* Forward declaration */
114+static void parse_addr_operand(TCCState *s1, Operand *op);
26115
27116 /* XXX: make it faster ? */
28117 ST_FUNC void g(int c)
@@ -37,16 +126,16 @@ ST_FUNC void g(int c) · 8 unmodified lines
37126 ind = ind1;
38127 }
39128
40−ST_FUNC void gen_le16 (int i)
129+ST_FUNC void gen_le16(int c)
41130 {
42− g(i);
43− g(i>>8);
131+ g(c);
132+ g(c >> 8);
44133 }
45134
46−ST_FUNC void gen_le32 (int i)
135+ST_FUNC void gen_le32(int c)
47136 {
48− gen_le16(i);
49− gen_le16(i>>16);
137+ gen_le16(c);
138+ gen_le16(c >> 16);
50139 }
51140
52141 ST_FUNC void gen_expr32(ExprValue *pe)
@@ -54,22 +143,1889 @@ ST_FUNC void gen_expr32(ExprValue *pe) · 1 unmodified line
54143 gen_le32(pe->v);
55144 }
56145
146+/* Emit 32-bit instruction */
147+static 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. */
158+static 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 */
188+static 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 */
213+static 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+
237+static 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+
259+static 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 */
277+static 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. */
330+static 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, ...] */
346+static 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 */
388+static 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+
399+static 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 */
405+static 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 */
411+static 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) */
417+static 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) */
442+static 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 */
467+static 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) */
478+static 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) */
524+static 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 */
545+static 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+
552+static void gen_b(int32_t offset)
553+{
554+ gen_b_or_bl(offset, ARM64_B);
555+}
556+
557+/* Generate BL (branch with link) */
558+static void gen_bl(int32_t offset)
559+{
560+ gen_b_or_bl(offset, ARM64_BL);
561+}
562+
563+/* Generate BR (branch to register) */
564+static 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) */
572+static 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 */
580+static 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 */
588+static 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 */
598+static 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+
607+static 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 */
613+static 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 */
619+static 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+
628+static 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+
689+static 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) */
722+static 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+
788+static const char *skip_constraint_modifiers(const char *p)
789+{
790+ while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
791+ p++;
792+ return p;
793+}
794+
795+static int is_valid_add_imm(int64_t val)
796+{
797+ return val >= 0 && val <= 4095;
798+}
799+
800+static 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+
812+static 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+
828+static 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+
837+static 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+
853+static 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+
866+static 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+
875+static 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+
891+static 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+
910+static 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+
928+static int operand_is_sp(const Operand *op)
929+{
930+ return op->reg_tok == TOK_ASM_sp;
931+}
932+
933+static 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+
947+static 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+
965+static 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 */
984+static void gen_nop(void)
985+{
986+ emit_instr32(ARM64_NOP);
987+}
988+
989+/* Generate shift operations (LSL, LSR, ASR, ROR) */
990+static 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 */
1072+static 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) */
1140+static 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 */
1163+static 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 */
1209+static 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 */
1231+static 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 */
1263+static 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 */
1358+static 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+
1440+static 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+
1493+static 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 */
1521+static 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 */
1550+static 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 */
1630+static 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 */
1665+static 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 */
571725 ST_FUNC void asm_opcode(TCCState *s1, int opcode)
581726 {
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+ }
601821 }
611822
1823+/* Substitute assembler operand */
621824 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
631825 {
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+ }
651930 }
661931
67−/* generate prolog and epilog code for asm statement */
681932 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
69− int nb_outputs, int is_output,
70− uint8_t *clobber_regs,
71− int out_reg)
1933+ int nb_outputs, int is_output,
1934+ uint8_t *clobber_regs,
1935+ int out_reg)
721936 {
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+ }
732029 }
742030
752031 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
@@ -77,17 +2033,247 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, · 1 unmodified line
772033 const uint8_t *clobber_regs,
782034 int *pout_reg)
792035 {
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+ }
802255 }
812256
2257+/* Handle clobber list */
822258 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
832259 {
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;
852271 }
862272
87−ST_FUNC int asm_parse_regvar (int t)
2273+/* Parse register variable - this is the ST_FUNC that tcc.h expects */
2274+ST_FUNC int asm_parse_regvar(int t)
882275 {
89− asm_error();
90− return -1;
2276+ return arm64_parse_regvar(t);
912277 }
922278
932279 /*************************************************************/
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
10321032 tcc_debug_line(s1);
10331033 parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
10341034 redo:
1035+#if !defined(TCC_TARGET_ARM64)
10351036 if (tok == '#') {
10361037 /* horrible gas comment */
10371038 while (tok != TOK_LINEFEED)
10381039 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) {
10401043 asm_parse_directive(s1, global);
10411044 } else if (tok == TOK_PPNUM) {
10421045 const char *p;
@@ -1176,6 +1179,9 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 133 unmodified lines
11761179 if (*str == 'c' || *str == 'n' ||
11771180 *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
11781181 *str == 'q' || *str == 'l' ||
1182+#ifdef TCC_TARGET_ARM64
1183+ *str == 'x' || *str == 's' || *str == 'd' || *str == 'Z' ||
1184+#endif
11791185 #ifdef TCC_TARGET_RISCV64
11801186 *str == 'z' ||
11811187 #endif
@@ -1196,7 +1202,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 14 unmodified lines
11961202 sv = *op->vt;
11971203 if (op->reg >= 0) {
11981204 sv.r = op->reg;
1199− if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
1205+ if (op->is_memory)
12001206 sv.r |= VT_LVAL;
12011207 }
12021208 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
12481254 if ((vtop->r & VT_LVAL) &&
12491255 ((vtop->r & VT_VALMASK) == VT_LLOCAL ||
12501256 (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+ ) {
12521263 gv(RC_INT);
12531264 }
12541265 }
tccpp.c+3−3
@@ -942,11 +942,11 @@ redo_start: · 941 unmodified lines
942942 else if (parse_flags & PARSE_FLAG_ASM_FILE)
943943 p = parse_line_comment(p - 1);
944944 }
945−#if !defined(TCC_TARGET_ARM)
945+#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
946946 else if (parse_flags & PARSE_FLAG_ASM_FILE)
947947 p = parse_line_comment(p - 1);
948948 #else
949− /* ARM assembly uses '#' for constants */
949+ /* ARM/ARM64 assembly uses '#' for constants */
950950 #endif
951951 break;
952952 _default:
@@ -2678,7 +2678,7 @@ maybe_newline: · 1725 unmodified lines
26782678 p++;
26792679 tok = TOK_TWOSHARPS;
26802680 } else {
2681−#if !defined(TCC_TARGET_ARM)
2681+#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
26822682 if (parse_flags & PARSE_FLAG_ASM_FILE) {
26832683 p = parse_line_comment(p - 1);
26842684 goto redo_no_start;
tcctok.h+5−1
@@ -421,10 +421,14 @@ · 420 unmodified lines
421421 #include "i386-tok.h"
422422 #endif
423423
424−#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
424+#if defined TCC_TARGET_ARM
425425 #include "arm-tok.h"
426426 #endif
427427
428+#if defined TCC_TARGET_ARM64
429+#include "arm64-tok.h"
430+#endif
431+
428432 #if defined TCC_TARGET_RISCV64
429433 #include "riscv64-tok.h"
430434 #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