fix identify_loops so that it actually identifies loops
[ajla.git] / c2-arm64.inc
blob3bd43c905753605566c3bc302c16aa8a6ed2627b
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  */
19 #define ARM64_AND_OR_EOR        0x0a000000U
20 #define  ARM64_AND_OR_EOR_AND           0x00000000U
21 #define  ARM64_AND_OR_EOR_REG_NOT       0x00200000U
22 #define  ARM64_AND_OR_EOR_IMM_NOT       0x00400000U
23 #define  ARM64_AND_OR_EOR_ORR           0x20000000U
24 #define  ARM64_AND_OR_EOR_EOR           0x40000000U
25 #define  ARM64_AND_OR_EOR_ANDS          0x60000000U
26 #define  ARM64_AND_OR_EOR_SIZE          0x80000000U
27 #define ARM64_ADDSUB_SHIFTED    0x0b000000U
28 #define ARM64_ADDSUB_EXTENDED   0x0b200000U
29 #define ARM64_CNT               0x0e205800U
30 #define ARM64_ADDV              0x0e31b800U
31 #define  ARM64_ADDV_SIZE                0x00c00000U
32 #define ARM64_ADDSUB_IMM        0x11000000U
33 #define  ARM64_ADDSUB_IMM_SHIFT12       0x00400000U
34 #define  ARM64_ADDSUB_SET_FLAGS         0x20000000U
35 #define  ARM64_ADDSUB_SUB               0x40000000U
36 #define  ARM64_ADDSUB_SIZE              0x80000000U
37 #define ARM64_AND_OR_EOR_IMM    0x12000000U
38 #define ARM64_MOVN_IMM16        0x12800000U
39 #define  ARM64_MOVN_IMM16_SIZE          0x80000000U
40 #define ARM64_SUBFM             0x13000000U
41 #define  ARM64_SUBFM_U                  0x40000000U
42 #define  ARM64_SUBFM_SIZE               0x80400000U
43 #define ARM64_EXTR              0x13800000U
44 #define  ARM64_EXTR_SIZE                0x80400000U
45 #define ARM64_B                 0x14000000U
46 #define ARM64_ADCSBC            0x1a000000U
47 #define  ARM64_ADCSBC_SET_FLAGS         0x20000000U
48 #define  ARM64_ADCSBC_SBC               0x40000000U
49 #define  ARM64_ADCSBC_SIZE              0x80000000U
50 #define ARM64_CSEL              0x1a800000U
51 #define  ARM64_CSEL_SEL                 0x00000000U
52 #define  ARM64_CSEL_INC                 0x00000400U
53 #define  ARM64_CSEL_INV                 0x40000000U
54 #define  ARM64_CSEL_NEG                 0x40000400U
55 #define  ARM64_CSEL_SIZE                0x80000000U
56 #define ARM64_CSET              0x1a9f07e0U
57 #define  ARM64_CSET_SIZE                0x80000000U
58 #define ARM64_SUDIV             0x1ac00800U
59 #define  ARM64_SUDIV_SDIV               0x00000400U
60 #define  ARM64_SUDIV_SIZE               0x80000000U
61 #define ARM64_ROT               0x1ac02000U
62 #define  ARM64_ROT_LSL                  0x00000000U
63 #define  ARM64_ROT_LSR                  0x00000400U
64 #define  ARM64_ROT_ASR                  0x00000800U
65 #define  ARM64_ROT_ROR                  0x00000c00U
66 #define  ARM64_ROT_SIZE                 0x80000000U
67 #define ARM64_MADDSUB           0x1b000000U
68 #define  ARM64_MADDSUB_MSUB             0x00008000U
69 #define  ARM64_MADDSUB_SIZE             0x80000000U
70 #define ARM64_FP_ALU            0x1e200800U
71 #define  ARM64_FP_ALU_MUL               0x00000000U
72 #define  ARM64_FP_ALU_DIV               0x00001000U
73 #define  ARM64_FP_ALU_ADD               0x00002000U
74 #define  ARM64_FP_ALU_SUB               0x00003000U
75 #define  ARM64_FP_ALU_SINGLE            0x00000000U
76 #define  ARM64_FP_ALU_DOUBLE            0x00400000U
77 #define  ARM64_FP_ALU_HALF              0x00c00000U
78 #define ARM64_FCMP              0x1e202000U
79 #define  ARM64_FCMP_ZERO                0x00000008U
80 #define  ARM64_FCMP_SINGLE              0x00000000U
81 #define  ARM64_FCMP_DOUBLE              0x00400000U
82 #define  ARM64_FCMP_HALF                0x00c00000U
83 #define ARM64_FP_ALU1           0x1e204000U
84 #define  ARM64_FP_ALU1_NEG              0x00010000U
85 #define  ARM64_FP_ALU1_SQRT             0x00018000U
86 #define  ARM64_FP_ALU1_RINTN            0x00040000U
87 #define  ARM64_FP_ALU1_RINTP            0x00048000U
88 #define  ARM64_FP_ALU1_RINTM            0x00050000U
89 #define  ARM64_FP_ALU1_RINTZ            0x00058000U
90 #define  ARM64_FP_ALU1_SINGLE           0x00000000U
91 #define  ARM64_FP_ALU1_DOUBLE           0x00400000U
92 #define  ARM64_FP_ALU1_HALF             0x00c00000U
93 #define ARM64_SCVTF             0x1e220000U
94 #define  ARM64_SCVTF_SINGLE             0x00000000U
95 #define  ARM64_SCVTF_DOUBLE             0x00400000U
96 #define  ARM64_SCVTF_HALF               0x00c00000U
97 #define  ARM64_SCVTF_SIZE               0x80000000U
98 #define ARM64_FCVT              0x1e224000U
99 #define  ARM64_FCVT_TO_SINGLE           0x00000000U
100 #define  ARM64_FCVT_TO_DOUBLE           0x00008000U
101 #define  ARM64_FCVT_TO_HALF             0x00018000U
102 #define  ARM64_FCVT_FROM_SINGLE         0x00000000U
103 #define  ARM64_FCVT_FROM_DOUBLE         0x00400000U
104 #define  ARM64_FCVT_FROM_HALF           0x00c00000U
105 #define ARM64_FMOV              0x1e260000U
106 #define  ARM64_FMOV_S_W                 0x00010000U
107 #define  ARM64_FMOV_D_X                 0x80410000U
108 #define ARM64_FCVTZS            0x1e380000U
109 #define  ARM64_FCVTZS_SINGLE            0x00000000U
110 #define  ARM64_FCVTZS_DOUBLE            0x00400000U
111 #define  ARM64_FCVTZS_HALF              0x00c00000U
112 #define  ARM64_FCVTZS_SIZE              0x80000000U
113 #define ARM64_LDPSTP            0x28000000U
114 #define  ARM64_LDPSTP_LD                0x00400000U
115 #define  ARM64_LDPSTP_POST_INDEX        0x00800000U
116 #define  ARM64_LDPSTP_IMM               0x01000000U
117 #define  ARM64_LDPSTP_PRE_INDEX         0x01800000U
118 #define  ARM64_LDPSTP_SIZE              0x80000000U
119 #define ARM64_MOV               0x2a0003e0U
120 #define  ARM64_MOV_SIZE                 0x80000000U
121 #define ARM64_CB                0x34000000U
122 #define  ARM64_CBZ_CBNZ                 0x01000000U
123 #define  ARM64_CBZ_SIZE                 0x80000000U
124 #define ARM64_TB                0x36000000U
125 #define  ARM64_TB_TBNZ                  0x01000000U
126 #define ARM64_LDST              0x38000000U
127 #define  ARM64_LDST_POST_INDEX          0x00000400U
128 #define  ARM64_LDST_PRE_INDEX           0x00000c00U
129 #define  ARM64_LDST_2REGS               0x00200800U
130 #define   ARM64_LDST_2REGS_UXTW                 0x00004000U
131 #define   ARM64_LDST_2REGS_NORMAL               0x00006000U
132 #define   ARM64_LDST_2REGS_SCALE                0x00007000U
133 #define   ARM64_LDST_2REGS_SXTW                 0x0000c000U
134 #define   ARM64_LDST_2REGS_SXTX                 0x0000e000U
135 #define  ARM64_LDST_ST                  0x00000000U
136 #define  ARM64_LDST_LD_UX               0x00400000U
137 #define  ARM64_LDST_LD_SX               0x00800000U
138 #define  ARM64_LDST_LD_SXW              0x00c00000U
139 #define  ARM64_LDST_SCALED_12BIT        0x01000000U
140 #define  ARM64_LDST_FP                  0x04000000U
141 #define  ARM64_LDST_SIZE1               0x40000000U
142 #define  ARM64_LDST_SIZE                0xc0000000U
143 #define  ARM64_LDST_FP_8                0x00000000U
144 #define  ARM64_LDST_FP_16               0x40000000U
145 #define  ARM64_LDST_FP_32               0x80000000U
146 #define  ARM64_LDST_FP_64               0xc0000000U
147 #define  ARM64_LDST_FP_128              0x00800000U
148 #define ARM64_MOV_IMM16         0x52800000U
149 #define  ARM64_MOV_IMM16_SIZE           0x80000000U
150 #define ARM64_B_COND            0x54000000U
151 #define ARM64_REV               0x5ac00000U
152 #define  ARM64_REV_1                    0x00000000U
153 #define  ARM64_REV_16                   0x00000400U
154 #define  ARM64_REV_32                   0x00000800U
155 #define  ARM64_REV_64                   0x00000c00U
156 #define  ARM64_REV_SIZE                 0x80000000U
157 #define ARM64_CLZ               0x5ac01000U
158 #define  ARM64_CLZ_SIZE                 0x80000000U
159 #define ARM64_MOVK              0x72800000U
160 #define  ARM64_MOVK_SIZE                0x80000000U
161 #define ARM64_SMADDSUBL         0x9b200000U
162 #define  ARM64_SMADDSUBL_SUB            0x00008000U
163 #define  ARM64_SMADDSUBL_U              0x00800000U
164 #define ARM64_SUMULH            0x9b407c00U
165 #define  ARM64_SUMULH_U                 0x00800000U
166 #define ARM64_BR                0xd61f0000U
167 #define ARM64_BLR               0xd63f0000U
168 #define ARM64_RET               0xd65f03c0U
170 static const int8_t jmp_cond[48] = {
171         0x6, 0x7, 0x3, 0x2, 0x0, 0x1, 0x9, 0x8,
172         0x4, 0x5,  -1,  -1, 0xb, 0xa, 0xd, 0xc,
173          -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
174          -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
175          -1,  -1, 0x3, 0x2, 0x0, 0x1, 0x9, 0x8,
176          -1,  -1, 0x6, 0x7,  -1,  -1,  -1,  -1,
179 static const int16_t rot_codes[8] = {
180         -1,
181         ARM64_ROT_ROR,
182         -1,
183         -1,
184         ARM64_ROT_LSL,
185         ARM64_ROT_LSR,
186         -1,
187         ARM64_ROT_ASR,
190 static bool attr_w cgen_ldr_str(struct codegen_context *ctx, unsigned ldst_mode, unsigned size, uint8_t reg, uint8_t *address)
192         int64_t imm;
193         uint32_t mc = ARM64_LDST;
194         mc |= ldst_mode;
195         mc |= ARM64_LDST_SIZE1 * size;
196         if (address[0] >= ARG_ADDRESS_2 && address[0] <= ARG_ADDRESS_2_SXTW) {
197                 imm = get_imm(&address[3]);
198                 if (unlikely(imm != 0))
199                         goto invalid;
200                 mc |= ARM64_LDST_2REGS;
201                 if (address[0] == ARG_ADDRESS_2) {
202                         mc |= ARM64_LDST_2REGS_NORMAL;
203                 } else if ((unsigned)address[0] - ARG_ADDRESS_2 == size) {
204                         mc |= ARM64_LDST_2REGS_SCALE;
205                 } else if (address[0] == ARG_ADDRESS_2_UXTW) {
206                         mc |= ARM64_LDST_2REGS_UXTW;
207                 } else if (address[0] == ARG_ADDRESS_2_SXTW) {
208                         mc |= ARM64_LDST_2REGS_SXTW;
209                 } else {
210                         goto invalid;
211                 }
212                 mc |= reg;
213                 mc |= (uint32_t)address[1] << 5;
214                 mc |= (uint32_t)address[2] << 16;
215                 cgen_four(mc);
216                 return true;
217         }
218         imm = get_imm(&address[2]);
219         if (imm >= -256 && imm <= 255) {
220                 if (address[0] == ARG_ADDRESS_1) {
221                 } else if (address[0] == ARG_ADDRESS_1_PRE_I) {
222                         mc |= ARM64_LDST_PRE_INDEX;
223                 } else if (address[0] == ARG_ADDRESS_1_POST_I) {
224                         mc |= ARM64_LDST_POST_INDEX;
225                 } else {
226                         goto invalid;
227                 }
228                 mc |= reg;
229                 mc |= (uint32_t)address[1] << 5;
230                 mc |= (imm & 0x1ff) << 12;
231                 cgen_four(mc);
232                 return true;
233         }
234         if (unlikely(address[0] != ARG_ADDRESS_1))
235                 goto invalid;
236         if (unlikely((imm & ((1 << size) - 1)) != 0) || unlikely(imm < 0))
237                 goto invalid;
238         imm >>= size;
239         if (unlikely(imm >= 0x1000))
240                 goto invalid;
241         mc |= ARM64_LDST_SCALED_12BIT;
242         mc |= reg;
243         mc |= (uint32_t)address[1] << 5;
244         mc |= (imm & 0xfff) << 10;
245         cgen_four(mc);
246         return true;
248 invalid:
249         internal(file_line, "cgen_ldr_str: invalid address: %02x, %02x, %"PRIxMAX"", reg, address[0], (uintmax_t)imm);
250         return false;
253 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
255         int64_t imm;
256         uint32_t mc;
257         uint8_t *arg1 = ctx->code_position;
258         uint8_t *arg2 = arg1 + arg_size(*arg1);
259         ctx->code_position = arg2 + arg_size(*arg2);
260         if (arg1[0] < 32) {
261                 if (arg2[0] < 32) {
262                         if (unlikely(sx))
263                                 internal(file_line, "cgen_mov: unsupported sign extension");
264                         if (unlikely(size < OP_SIZE_4))
265                                 internal(file_line, "cgen_mov: unsupported size %u", size);
266                         if (arg1[0] == R_SP || arg2[0] == R_SP) {
267                                 mc = ARM64_ADDSUB_IMM;
268                                 mc |= arg1[0];
269                                 mc |= (uint32_t)arg2[0] << 5;
270                         } else {
271                                 /* !!! TODO: handle shifted register */
272                                 mc = ARM64_MOV;
273                                 mc |= arg1[0];
274                                 mc |= (uint32_t)arg2[0] << 16;
275                         }
276                         mc |= ARM64_MOV_SIZE * (size == OP_SIZE_8);
277                         cgen_four(mc);
278                         return true;
279                 }
280                 if (arg2[0] == ARG_IMM) {
281                         if (unlikely(size < OP_SIZE_4))
282                                 internal(file_line, "cgen_mov: unsupported size %u", size);
283                         imm = get_imm(&arg2[1]);
284                         if (imm >= 0 && imm < 0x10000) {
285                                 mc = ARM64_MOV_IMM16;
286                                 mc |= ARM64_MOV_IMM16_SIZE * (size == OP_SIZE_8);
287                                 mc |= arg1[0];
288                                 mc |= (uint32_t)imm << 5;
289                                 cgen_four(mc);
290                                 return true;
291                         }
292                         if (~imm >= 0 && ~imm < 0x10000) {
293                                 imm = ~imm;
294                                 mc = ARM64_MOVN_IMM16;
295                                 mc |= ARM64_MOVN_IMM16_SIZE * (size == OP_SIZE_8);
296                                 mc |= arg1[0];
297                                 mc |= (uint32_t)imm << 5;
298                                 cgen_four(mc);
299                                 return true;
300                         }
301                         internal(file_line, "cgen_mov: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
302                 }
303                 if (!sx || size == OP_SIZE_NATIVE)
304                         return cgen_ldr_str(ctx, ARM64_LDST_LD_UX, size, arg1[0], arg2);
305                 else
306                         return cgen_ldr_str(ctx, ARM64_LDST_LD_SX, size, arg1[0], arg2);
307         }
308         if (arg1[0] < 64) {
309                 if (arg2[0] < 32) {
310                         if (size < OP_SIZE_4)
311                                 goto invalid;
312                         mc = ARM64_FMOV | (size == OP_SIZE_4 ? ARM64_FMOV_S_W : ARM64_FMOV_D_X);
313                         mc |= arg1[0] & 31;
314                         mc |= (uint32_t)arg2[0] << 5;
315                         cgen_four(mc);
316                         return true;
317                 }
318                 if (arg2[0] < 64)
319                         goto invalid;
320                 return cgen_ldr_str(ctx, ARM64_LDST_LD_UX | ARM64_LDST_FP, size, arg1[0] & 31, arg2);
321         }
322         if (arg2[0] < 31) {
323                 return cgen_ldr_str(ctx, ARM64_LDST_ST, size, arg2[0], arg1);
324         }
325         if (arg2[0] < 64) {
326                 return cgen_ldr_str(ctx, ARM64_LDST_ST | ARM64_LDST_FP, size, arg2[0] & 31, arg1);
327         }
328         if (arg2[0] == ARG_IMM) {
329                 imm = get_imm(&arg2[1]);
330                 if (!imm)
331                         return cgen_ldr_str(ctx, ARM64_LDST_ST, size, 0x1f, arg1);
332         }
333 invalid:
334         internal(file_line, "cgen_mov: invalid arguments %02x, %02x", arg1[0], arg2[0]);
335         return false;
338 static bool attr_w cgen_alu_args(struct codegen_context *ctx, unsigned size, unsigned writes_flags, unsigned alu, bool not, uint8_t *arg1, uint8_t *arg2, uint8_t *arg3)
340         uint32_t mc;
341         int64_t imm;
342         uint8_t z = 31;
343         if (unlikely(arg1[0] >= 32))
344                 goto invalid;
345         if (unlikely(alu == ALU_MUL)) {
346                 mc = ARM64_MADDSUB;
347                 if (size == OP_SIZE_8 &&
348                     arg2[0] == ARG_EXTENDED_REGISTER && arg2[1] == ARG_EXTEND_SXTW &&
349                     arg3[0] == ARG_EXTENDED_REGISTER && arg3[1] == ARG_EXTEND_SXTW) {
350                         arg2 += 2;
351                         arg3 += 2;
352                         mc = ARM64_SMADDSUBL;
353                 } else if (size == OP_SIZE_8 &&
354                            arg2[0] == ARG_EXTENDED_REGISTER && arg2[1] == ARG_EXTEND_UXTW &&
355                            arg3[0] == ARG_EXTENDED_REGISTER && arg3[1] == ARG_EXTEND_UXTW) {
356                         arg2 += 2;
357                         arg3 += 2;
358                         mc = ARM64_SMADDSUBL | ARM64_SMADDSUBL_U;
359                 }
360                 if (unlikely(arg2[0] >= 32) && unlikely(arg3[0] >= 32))
361                         goto invalid;
362                 mc |= ARM64_MADDSUB_SIZE * (size == OP_SIZE_8);
363                 mc |= arg1[0];
364                 mc |= 0x1fU << 10;
365                 mc |= arg2[0] << 5;
366                 mc |= arg3[0] << 16;
367                 cgen_four(mc);
368                 return true;
369         }
370         if (unlikely(arg2[0] >= 32))
371                 goto invalid;
372         if (unlikely(alu == ALU_UMULH) || unlikely(alu == ALU_SMULH)) {
373                 if (unlikely(arg3[0] >= 32))
374                         goto invalid;
375                 if (unlikely(size != OP_SIZE_8))
376                         goto invalid;
377                 mc = ARM64_SUMULH;
378                 mc |= ARM64_SUMULH_U * (alu == ALU_UMULH);
379                 mc |= arg1[0];
380                 mc |= (uint32_t)arg2[0] << 5;
381                 mc |= (uint32_t)arg3[0] << 16;
382                 cgen_four(mc);
383                 return true;
384         }
385         if (unlikely(alu == ALU_UDIV) || unlikely(alu == ALU_SDIV)) {
386                 if (unlikely(arg3[0] >= 32))
387                         goto invalid;
388                 mc = ARM64_SUDIV;
389                 mc |= ARM64_SUDIV_SDIV * (alu == ALU_SDIV);
390                 mc |= ARM64_SUDIV_SIZE * (size == OP_SIZE_8);
391                 mc |= arg1[0];
392                 mc |= (uint32_t)arg2[0] << 5;
393                 mc |= (uint32_t)arg3[0] << 16;
394                 cgen_four(mc);
395                 return true;
396         }
397         if (unlikely(alu == ALU_ADC) || unlikely(alu == ALU_SBB)) {
398                 if (arg3[0] == ARG_IMM) {
399                         imm = get_imm(&arg3[1]);
400                         if (unlikely(imm != 0))
401                                 goto invalid;
402                         arg3 = &z;
403                 } else if (unlikely(arg3[0] >= 32)) {
404                         goto invalid;
405                 }
406                 mc = ARM64_ADCSBC;
407                 mc |= ARM64_ADCSBC_SBC * (alu == ALU_SBB);
408 reg_reg_reg:
409                 mc |= ARM64_ADCSBC_SET_FLAGS * (uint32_t)!!writes_flags;
410 reg_reg_reg_2:
411                 mc |= ARM64_ADCSBC_SIZE * (size == OP_SIZE_8);
412                 mc |= arg1[0];
413                 mc |= (uint32_t)arg2[0] << 5;
414                 mc |= (uint32_t)arg3[0] << 16;
415                 cgen_four(mc);
416                 return true;
417         }
418         if (alu == ALU_ADD || alu == ALU_SUB) {
419                 mc = 0;
420                 mc |= ARM64_ADDSUB_SUB * (alu == ALU_SUB);
421                 if (arg3[0] < 32) {
422                         mc |= ARM64_ADDSUB_SHIFTED;
423                         goto reg_reg_reg;
424                 }
425                 if (arg3[0] == ARG_EXTENDED_REGISTER) {
426                         mc |= ARM64_ADDSUB_EXTENDED;
427                         mc |= (uint32_t)arg3[1] << 10;
428                         arg3 += 2;
429                         goto reg_reg_reg;
430                 }
431                 if (arg3[0] == ARG_SHIFTED_REGISTER) {
432                         if (unlikely((arg3[1] >> 6) == 3))
433                                 goto invalid;
434                         mc |= ARM64_ADDSUB_SHIFTED;
435                         mc |= (uint32_t)(arg3[1] & ARG_SHIFT_AMOUNT) << 10;
436                         mc |= (uint32_t)(arg3[1] >> 6) << 22;
437                         arg3 += 2;
438                         goto reg_reg_reg;
439                 }
440                 if (arg3[0] == ARG_IMM) {
441                         mc |= ARM64_ADDSUB_IMM;
442                         mc |= ARM64_ADCSBC_SET_FLAGS * (uint32_t)!!writes_flags;
443                         imm = get_imm(&arg3[1]);
444                         if (likely(imm >= 0) && likely(imm < 0x1000)) {
445 reg_reg_imm:
446                                 mc |= imm << 10;
447                                 mc |= arg1[0];
448                                 mc |= (uint32_t)arg2[0] << 5;
449                                 mc |= ARM64_ADCSBC_SIZE * (size == OP_SIZE_8);
450                                 cgen_four(mc);
451                                 return true;
452                         }
453                         if (likely(!(imm & 0xfff))) {
454                                 imm = (uint64_t)imm >> 12;
455                                 if (likely(imm < 0x1000)) {
456                                         mc |= ARM64_ADDSUB_IMM_SHIFT12;
457                                         goto reg_reg_imm;
458                                 }
459                         }
460                 }
461                 goto invalid;
462         }
463         if (alu == ALU_AND || alu == ALU_OR || alu == ALU_XOR) {
464                 mc = 0;
465                 if (not) {
466                         if (arg3[0] != ARG_IMM)
467                                 mc |= ARM64_AND_OR_EOR_REG_NOT;
468                 }
469                 if (alu == ALU_AND) {
470                         mc |= writes_flags ? ARM64_AND_OR_EOR_ANDS : ARM64_AND_OR_EOR_AND;
471                 } else {
472                         if (unlikely(writes_flags))
473                                 goto invalid;
474                         mc |= alu == ALU_OR ? ARM64_AND_OR_EOR_ORR : ARM64_AND_OR_EOR_EOR;
475                 }
476                 if (arg3[0] < 32) {
477                         mc |= ARM64_AND_OR_EOR;
478                         goto reg_reg_reg_2;
479                 }
480                 if (arg3[0] == ARG_SHIFTED_REGISTER) {
481                         mc |= ARM64_AND_OR_EOR;
482                         mc |= (uint32_t)(arg3[1] & ARG_SHIFT_AMOUNT) << 10;
483                         mc |= (uint32_t)(arg3[1] >> 6) << 22;
484                         arg3 += 2;
485                         goto reg_reg_reg_2;
486                 }
487                 if (arg3[0] == ARG_IMM) {
488                         int16_t code;
489                         mc |= ARM64_AND_OR_EOR_SIZE * (size == OP_SIZE_8);
490                         mc |= ARM64_AND_OR_EOR_IMM;
491                         imm = get_imm(&arg3[1]);
492                         if (not)
493                                 imm = ~imm;
494                         if (size == OP_SIZE_4)
495                                 imm &= 0xffffffff;
496                         code = value_to_code(size, imm);
497                         if (unlikely(code < 0))
498                                 internal(file_line, "cgen_alu_args: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
499                         mc |= arg1[0];
500                         mc |= (uint32_t)arg2[0] << 5;
501                         mc ^= (uint32_t)code << 10;
502                         cgen_four(mc);
503                         return true;
504                 }
505                 goto invalid;
506         }
508 invalid:
509         internal(file_line, "cgen_alu_args: invalid arguments %02x, %02x, %02x, %u, %u", arg1[0], arg2[0], arg3[0], alu, writes_flags);
510         return false;
513 static bool attr_w cgen_cmp(struct codegen_context *ctx, unsigned size, bool cmn)
515         uint8_t z = 31;
516         uint8_t *arg1 = ctx->code_position;
517         uint8_t *arg2 = arg1 + arg_size(*arg1);
518         ctx->code_position = arg2 + arg_size(*arg2);
519         return cgen_alu_args(ctx, size, true, cmn ? ALU_ADD : ALU_SUB, false, &z, arg1, arg2);
522 static bool attr_w cgen_test(struct codegen_context *ctx, unsigned size)
524         uint8_t z = 31;
525         uint8_t *arg1 = ctx->code_position;
526         uint8_t *arg2 = arg1 + arg_size(*arg1);
527         ctx->code_position = arg2 + arg_size(*arg2);
528         return cgen_alu_args(ctx, size, true, ALU_AND, false, &z, arg1, arg2);
531 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned writes_flags, unsigned alu)
533         bool not;
534         uint8_t *arg1 = ctx->code_position;
535         uint8_t *arg2 = arg1 + arg_size(*arg1);
536         uint8_t *arg3 = arg2 + arg_size(*arg2);
537         ctx->code_position = arg3 + arg_size(*arg3);
538         not = false;
539         switch (alu) {
540                 case ALU_ORN:   alu = ALU_OR; not = true; break;
541                 case ALU_ANDN:  alu = ALU_AND; not = true; break;
542                 case ALU_XORN:  alu = ALU_XOR; not = true; break;
543         }
544         return cgen_alu_args(ctx, size, writes_flags, alu, not, arg1, arg2, arg3);
547 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned writes_flags, unsigned alu)
549         uint32_t mc = 0;
550         uint8_t z = 31;
551         uint8_t one_imm[9] = { ARG_IMM, 1, 0, 0, 0, 0, 0, 0, 0 };
552         uint8_t *arg1 = ctx->code_position;
553         uint8_t *arg2 = arg1 + arg_size(*arg1);
554         ctx->code_position = arg2 + arg_size(*arg2);
555         switch (alu) {
556                 case ALU1_NOT:
557                         return cgen_alu_args(ctx, size, writes_flags, ALU_OR, true, arg1, &z, arg2);
558                 case ALU1_NEG:
559                         return cgen_alu_args(ctx, size, writes_flags, ALU_SUB, false, arg1, &z, arg2);
560                 case ALU1_NGC:
561                         return cgen_alu_args(ctx, size, writes_flags, ALU_SBB, false, arg1, &z, arg2);
562                 case ALU1_INC:
563                         return cgen_alu_args(ctx, size, writes_flags, ALU_ADD, false, arg1, arg2, one_imm);
564                 case ALU1_DEC:
565                         return cgen_alu_args(ctx, size, writes_flags, ALU_SUB, false, arg1, arg2, one_imm);
566                 case ALU1_BSWAP:
567                 case ALU1_BSWAP16:
568                 case ALU1_BREV:
569                         mc = ARM64_REV;
570                         if (alu == ALU1_BREV) {
571                                 mc |= ARM64_REV_1;
572                         } else if (alu == ALU1_BSWAP16) {
573                                 mc |= ARM64_REV_16;
574                         } else if (alu == ALU1_BSWAP) {
575                                 if (size == OP_SIZE_4)
576                                         mc |= ARM64_REV_32;
577                                 else
578                                         mc |= ARM64_REV_64;
579                         }
580                         mc |= ARM64_REV_SIZE * (size == OP_SIZE_8);
581                         mc |= arg1[0];
582                         mc |= (uint32_t)arg2[0] << 5;
583                         cgen_four(mc);
584                         return true;
585                 case ALU1_LZCNT:
586                         mc = ARM64_CLZ;
587                         mc |= ARM64_CLZ_SIZE * (size == OP_SIZE_8);
588                         mc |= arg1[0];
589                         mc |= (uint32_t)arg2[0] << 5;
590                         cgen_four(mc);
591                         return true;
592                 default:
593                         internal(file_line, "cgen_alu1: invalid arguments");
594                         return false;
595         }
598 static bool attr_w cgen_rot_imm(struct codegen_context *ctx, unsigned size, uint8_t rot, uint8_t *arg1, uint8_t *arg2, uint8_t imm)
600         uint64_t mc;
601         if (unlikely(rot == ROT_ROL) || rot == ROT_SHL) {
602                 imm = -imm;
603         }
604         imm &= (1U << (size + 3)) - 1;
605         mc = 0;
606         mc |= (rot == ROT_ROR || rot == ROT_ROL ? ARM64_EXTR_SIZE : ARM64_SUBFM_SIZE) * (size == OP_SIZE_8);
607         switch (rot) {
608                 case ROT_ROL:
609                 case ROT_ROR:
610                         mc |= ARM64_EXTR;
611                         mc |= arg1[0];
612                         mc |= (uint32_t)arg2[0] << 5;
613                         mc |= (uint32_t)arg2[0] << 16;
614                         mc |= (uint32_t)imm << 10;
615                         break;
616                 case ROT_SHL:
617                         mc |= ARM64_SUBFM | ARM64_SUBFM_U;
618                         mc |= arg1[0];
619                         mc |= (uint32_t)arg2[0] << 5;
620                         mc |= (uint32_t)imm << 16;
621                         imm--;
622                         imm &= (1U << (size + 3)) - 1;
623                         mc |= (uint32_t)(imm << 10);
624                         break;
625                 case ROT_SHR:
626                 case ROT_SAR:
627                         mc |= ARM64_SUBFM;
628                         mc |= (rot == ROT_SHR) * ARM64_SUBFM_U;
629                         mc |= arg1[0];
630                         mc |= (uint32_t)arg2[0] << 5;
631                         mc |= (uint32_t)imm << 16;
632                         mc |= ((1U << (size + 3)) - 1) << 10;
633                         break;
634         }
635         cgen_four(mc);
636         return true;
639 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned rot)
641         int16_t arm_rot;
642         uint32_t mc;
643         uint8_t *arg1 = ctx->code_position;
644         uint8_t *arg2 = arg1 + arg_size(*arg1);
645         uint8_t *arg3 = arg2 + arg_size(*arg2);
646         ctx->code_position = arg3 + arg_size(*arg3);
647         if (arg3[0] == ARG_IMM)
648                 return cgen_rot_imm(ctx, size, rot, arg1, arg2, arg3[1]);
649         arm_rot = rot_codes[rot];
650         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32) || unlikely(arm_rot < 0))
651                 internal(file_line, "cgen_rot: invalid arguments");
652         mc = ARM64_ROT;
653         mc |= ARM64_ROT_SIZE * (size == OP_SIZE_8);
654         mc |= arm_rot;
655         mc |= arg1[0];
656         mc |= (uint32_t)arg2[0] << 5;
657         mc |= (uint32_t)arg3[0] << 16;
658         cgen_four(mc);
659         return true;
662 static bool attr_w cgen_madd(struct codegen_context *ctx, unsigned size, bool sub)
664         uint32_t mc;
665         uint8_t *arg1 = ctx->code_position;
666         uint8_t *arg2 = arg1 + arg_size(*arg1);
667         uint8_t *arg3 = arg2 + arg_size(*arg2);
668         uint8_t *arg4 = arg3 + arg_size(*arg3);
669         ctx->code_position = arg4 + arg_size(*arg4);
670         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32) || unlikely(arg4[0] >= 32))
671                 internal(file_line, "cgen_madd: invalid arguments");
672         mc = ARM64_MADDSUB;
673         mc |= ARM64_MADDSUB_SIZE * (size == OP_SIZE_8);
674         mc |= ARM64_MADDSUB_MSUB * sub;
675         mc |= arg1[0];
676         mc |= (uint32_t)arg2[0] << 5;
677         mc |= (uint32_t)arg3[0] << 16;
678         mc |= (uint32_t)arg4[0] << 10;
679         cgen_four(mc);
680         return true;
683 static bool attr_w cgen_set_cond(struct codegen_context *ctx, unsigned size, unsigned aux)
685         int8_t cond;
686         uint32_t mc;
687         uint8_t *arg1 = ctx->code_position;
688         ctx->code_position = arg1 + arg_size(*arg1);
689         cond = jmp_cond[aux];
690         if (unlikely(cond < 0) || unlikely(arg1[0] >= 31))
691                 internal(file_line, "cgen_set_cond: invalid arguments: %02x, %u, %u", arg1[0], size, aux);
692         mc = ARM64_CSET;
693         mc |= ARM64_CSET_SIZE * (size == OP_SIZE_8);
694         mc |= (uint32_t)(cond ^ 1) << 12;
695         mc |= arg1[0];
696         cgen_four(mc);
697         return true;
700 static bool attr_w cgen_csel(struct codegen_context *ctx, uint32_t insn, unsigned size, unsigned aux)
702         uint32_t mc;
703         int8_t cond;
704         uint8_t z = 31;
705         int64_t imm;
706         uint8_t *arg1 = ctx->code_position;
707         uint8_t *arg2 = arg1 + arg_size(*arg1);
708         uint8_t *arg3 = arg2 + arg_size(*arg2);
709         ctx->code_position = arg3 + arg_size(*arg3);
710         if (arg2[0] == ARG_IMM) {
711                 imm = get_imm(&arg2[1]);
712                 if (unlikely(imm != 0))
713                         goto invalid;
714                 arg2 = &z;
715         }
716         if (arg3[0] == ARG_IMM) {
717                 imm = get_imm(&arg3[1]);
718                 if (unlikely(imm != 0))
719                         goto invalid;
720                 arg3 = &z;
721         }
722         cond = jmp_cond[aux];
723         if (unlikely(cond < 0))
724                 goto invalid;
725         mc = ARM64_CSEL;
726         switch (insn) {
727                 case INSN_CSEL_SEL:     mc |= ARM64_CSEL_SEL; break;
728                 case INSN_CSEL_INC:     mc |= ARM64_CSEL_INC; break;
729                 case INSN_CSEL_INV:     mc |= ARM64_CSEL_INV; break;
730                 case INSN_CSEL_NEG:     mc |= ARM64_CSEL_NEG; break;
731                 default:
732                         goto invalid;
733         }
734         mc |= ARM64_CSEL_SIZE * (size == OP_SIZE_8);
735         mc |= arg1[0];
736         mc |= (uint32_t)arg2[0] << 16;
737         mc |= (uint32_t)arg3[0] << 5;
738         mc |= (uint32_t)cond << 12;
739         cgen_four(mc);
740         return true;
741 invalid:
742         internal(file_line, "cgen_csel: invalid arguments");
745 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr, unsigned size)
747         uint8_t *arg1, *arg2, *arg3;
748         uint8_t z = 31;
749         uint32_t mc;
750         int64_t imm;
751         if (!ldr) {
752                 arg1 = ctx->code_position;
753                 arg2 = arg1 + arg_size(*arg1);
754                 arg3 = arg2 + arg_size(*arg2);
755                 ctx->code_position = arg3 + arg_size(*arg3);
756                 if (arg2[0] == ARG_IMM) {
757                         imm = get_imm(&arg2[1]);
758                         if (unlikely(imm != 0))
759                                 goto invalid;
760                         arg2 = &z;
761                 }
762                 if (arg3[0] == ARG_IMM) {
763                         imm = get_imm(&arg3[1]);
764                         if (unlikely(imm != 0))
765                                 goto invalid;
766                         arg3 = &z;
767                 }
768         } else {
769                 arg2 = ctx->code_position;
770                 arg3 = arg2 + arg_size(*arg2);
771                 arg1 = arg3 + arg_size(*arg3);
772                 ctx->code_position = arg1 + arg_size(*arg1);
773         }
774         mc = ARM64_LDPSTP;
775         mc |= ARM64_LDPSTP_LD * (uint32_t)ldr;
776         mc |= ARM64_LDPSTP_SIZE * (size == OP_SIZE_8);
777         if (arg1[0] == ARG_ADDRESS_1) {
778                 mc |= ARM64_LDPSTP_IMM;
779         } else if (arg1[0] == ARG_ADDRESS_1_PRE_I) {
780                 mc |= ARM64_LDPSTP_PRE_INDEX;
781         } else if (arg1[0] == ARG_ADDRESS_1_POST_I) {
782                 mc |= ARM64_LDPSTP_POST_INDEX;
783         } else {
784                 goto invalid;
785         }
786         if (unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32))
787                 goto invalid;
788         mc |= arg2[0];
789         mc |= (uint32_t)arg3[0] << 10;
790         mc |= (uint32_t)arg1[1] << 5;
791         imm = get_imm(&arg1[2]);
792         if (unlikely((imm & ((1 << size) - 1)) != 0))
793                 goto invalid;
794         imm /= 1 << size;
795         if (unlikely(imm < -64) || unlikely(imm > 63))
796                 goto invalid;
797         mc |= (imm & 127) << 15;
798         cgen_four(mc);
799         return true;
801 invalid:
802         internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
803         return false;
806 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
808         uint32_t mc;
809         uint64_t imm;
810         uint8_t *arg1 = ctx->code_position;
811         uint8_t *arg2 = arg1 + arg_size(*arg1);
812         uint8_t *arg3 = arg2 + arg_size(*arg2);
813         ctx->code_position = arg3 + arg_size(*arg3);
814         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] != ARG_IMM))
815                 internal(file_line, "cgen_mov_mask: bad arguments");
816         mc = ARM64_MOVK;
817         mc |= ARM64_MOVK_SIZE;
818         mc |= (uint32_t)aux << 21;
819         imm = get_imm(&arg3[1]);
820         if (unlikely(imm >= 0x10000))
821                 internal(file_line, "cgen_mov_mask: bad number");
822         mc |= (imm & 0xffff) << 5;
823         mc |= arg1[0];
824         cgen_four(mc);
825         return true;
828 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
830         uint32_t mc;
831         uint8_t *arg1 = ctx->code_position;
832         uint8_t *arg2 = arg1 + arg_size(*arg1);
833         ctx->code_position = arg2 + arg_size(*arg2);
834         mc = ARM64_FCMP;
835         switch (op_size) {
836                 case OP_SIZE_2:         mc |= ARM64_FCMP_HALF; break;
837                 case OP_SIZE_4:         mc |= ARM64_FCMP_SINGLE; break;
838                 case OP_SIZE_8:         mc |= ARM64_FCMP_DOUBLE; break;
839                 default:                internal(file_line, "cgen_fp_cmp: invalid size %u", op_size);
840         }
841         mc |= ((uint32_t)(arg1[0] & 31)) << 5;
842         mc |= ((uint32_t)(arg2[0] & 31)) << 16;
843         cgen_four(mc);
844         return true;
847 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
849         uint32_t mc;
850         uint8_t *arg1 = ctx->code_position;
851         uint8_t *arg2 = arg1 + arg_size(*arg1);
852         uint8_t *arg3 = arg2 + arg_size(*arg2);
853         ctx->code_position = arg3 + arg_size(*arg3);
854         mc = ARM64_FP_ALU;
855         switch (aux) {
856                 case FP_ALU_ADD:        mc |= ARM64_FP_ALU_ADD; break;
857                 case FP_ALU_SUB:        mc |= ARM64_FP_ALU_SUB; break;
858                 case FP_ALU_MUL:        mc |= ARM64_FP_ALU_MUL; break;
859                 case FP_ALU_DIV:        mc |= ARM64_FP_ALU_DIV; break;
860                 default:                internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
861         }
862         switch (op_size) {
863                 case OP_SIZE_2:         mc |= ARM64_FP_ALU_HALF; break;
864                 case OP_SIZE_4:         mc |= ARM64_FP_ALU_SINGLE; break;
865                 case OP_SIZE_8:         mc |= ARM64_FP_ALU_DOUBLE; break;
866                 default:                internal(file_line, "cgen_fp_alu: invalid size %u", op_size);
867         }
868         mc |= arg1[0] & 31;
869         mc |= ((uint32_t)(arg2[0] & 31)) << 5;
870         mc |= ((uint32_t)(arg3[0] & 31)) << 16;
871         cgen_four(mc);
872         return true;
875 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
877         uint32_t mc;
878         uint8_t *arg1 = ctx->code_position;
879         uint8_t *arg2 = arg1 + arg_size(*arg1);
880         ctx->code_position = arg2 + arg_size(*arg2);
881         switch (aux) {
882                 case FP_ALU1_NEG:       mc = ARM64_FP_ALU1 | ARM64_FP_ALU1_NEG; break;
883                 case FP_ALU1_SQRT:      mc = ARM64_FP_ALU1 | ARM64_FP_ALU1_SQRT; break;
884                 case FP_ALU1_ROUND:     mc = ARM64_FP_ALU1 | ARM64_FP_ALU1_RINTN; break;
885                 case FP_ALU1_FLOOR:     mc = ARM64_FP_ALU1 | ARM64_FP_ALU1_RINTM; break;
886                 case FP_ALU1_CEIL:      mc = ARM64_FP_ALU1 | ARM64_FP_ALU1_RINTP; break;
887                 case FP_ALU1_TRUNC:     mc = ARM64_FP_ALU1 | ARM64_FP_ALU1_RINTZ; break;
888                 case FP_ALU1_VCNT8:     mc = ARM64_CNT; goto do_regs;
889                 case FP_ALU1_ADDV:      mc = ARM64_ADDV; goto do_regs;
890                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
891         }
892         switch (op_size) {
893                 case OP_SIZE_2:         mc |= ARM64_FP_ALU1_HALF; break;
894                 case OP_SIZE_4:         mc |= ARM64_FP_ALU1_SINGLE; break;
895                 case OP_SIZE_8:         mc |= ARM64_FP_ALU1_DOUBLE; break;
896                 default:                internal(file_line, "cgen_fp_alu1: invalid size %u", op_size);
897         }
898 do_regs:
899         mc |= arg1[0] & 31;
900         mc |= ((uint32_t)(arg2[0] & 31)) << 5;
901         cgen_four(mc);
902         return true;
905 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
907         uint32_t mc;
908         uint8_t *arg1 = ctx->code_position;
909         uint8_t *arg2 = arg1 + arg_size(*arg1);
910         ctx->code_position = arg2 + arg_size(*arg2);
911         mc = ARM64_FCVTZS;
912         switch (int_op_size) {
913                 case OP_SIZE_4:         break;
914                 case OP_SIZE_8:         mc |= ARM64_FCVTZS_SIZE; break;
915                 default:                internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
916         }
917         switch (fp_op_size) {
918                 case OP_SIZE_2:         mc |= ARM64_FCVTZS_HALF; break;
919                 case OP_SIZE_4:         mc |= ARM64_FCVTZS_SINGLE; break;
920                 case OP_SIZE_8:         mc |= ARM64_FCVTZS_DOUBLE; break;
921                 default:                internal(file_line, "cgen_fp_to_int: invalid fp size %u", fp_op_size);
922         }
923         mc |= arg1[0];
924         mc |= ((uint32_t)(arg2[0] & 31)) << 5;
925         cgen_four(mc);
926         return true;
929 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
931         uint32_t mc;
932         uint8_t *arg1 = ctx->code_position;
933         uint8_t *arg2 = arg1 + arg_size(*arg1);
934         ctx->code_position = arg2 + arg_size(*arg2);
935         mc = ARM64_SCVTF;
936         switch (int_op_size) {
937                 case OP_SIZE_4:         break;
938                 case OP_SIZE_8:         mc |= ARM64_SCVTF_SIZE; break;
939                 default:                internal(file_line, "cgen_fp_from_int: invalid int size %u", int_op_size);
940         }
941         switch (fp_op_size) {
942                 case OP_SIZE_2:         mc |= ARM64_SCVTF_HALF; break;
943                 case OP_SIZE_4:         mc |= ARM64_SCVTF_SINGLE; break;
944                 case OP_SIZE_8:         mc |= ARM64_SCVTF_DOUBLE; break;
945                 default:                internal(file_line, "cgen_fp_from_int: invalid fp size %u", fp_op_size);
946         }
947         mc |= arg1[0] & 31;
948         mc |= ((uint32_t)arg2[0]) << 5;
949         cgen_four(mc);
950         return true;
953 static bool attr_w cgen_fp_cvt(struct codegen_context *ctx, unsigned from_op_size, unsigned to_op_size)
955         uint32_t mc;
956         uint8_t *arg1 = ctx->code_position;
957         uint8_t *arg2 = arg1 + arg_size(*arg1);
958         ctx->code_position = arg2 + arg_size(*arg2);
959         mc = ARM64_FCVT;
960         switch (from_op_size) {
961                 case OP_SIZE_2: mc |= ARM64_FCVT_FROM_HALF; break;
962                 case OP_SIZE_4: mc |= ARM64_FCVT_FROM_SINGLE; break;
963                 case OP_SIZE_8: mc |= ARM64_FCVT_FROM_DOUBLE; break;
964                 default:        internal(file_line, "cgen_fp_cvt: invalid types %u, %u", from_op_size, to_op_size);
965         }
966         switch (to_op_size) {
967                 case OP_SIZE_2: mc |= ARM64_FCVT_TO_HALF; break;
968                 case OP_SIZE_4: mc |= ARM64_FCVT_TO_SINGLE; break;
969                 case OP_SIZE_8: mc |= ARM64_FCVT_TO_DOUBLE; break;
970                 default:        internal(file_line, "cgen_fp_cvt: invalid types %u, %u", from_op_size, to_op_size);
971         }
972         mc |= arg1[0] & 31;
973         mc |= ((uint32_t)arg2[0] & 31) << 5;
974         cgen_four(mc);
975         return true;
978 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned aux, unsigned length)
980         int8_t cond = jmp_cond[aux];
981         if (unlikely(cond < 0))
982                 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
983         switch (length) {
984                 case JMP_SHORTEST:
985                 case JMP_SHORT:
986                         g(add_relocation(ctx, JMP_SHORT, 0, NULL));
987                         cgen_four(ARM64_B_COND | cond);
988                         return true;
989                 case JMP_LONG:
990                         cgen_four(ARM64_B_COND | (cond ^ 1) | 0x40);
991                         g(add_relocation(ctx, JMP_LONG, 0, NULL));
992                         cgen_four(ARM64_B);
993                         return true;
994                 default:
995                         internal(file_line, "cgen_jmp_cond: invalid length %u", length);
996                         return false;
997         }
1000 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned size, unsigned aux, unsigned length)
1002         uint32_t mc = ARM64_CB;
1003         mc |= ARM64_CBZ_SIZE * (size == OP_SIZE_8);
1004         mc |= cget_one(ctx);
1005         switch (aux) {
1006                 case COND_E:
1007                         break;
1008                 case COND_NE:
1009                         mc |= ARM64_CBZ_CBNZ;
1010                         break;
1011                 default:
1012                         internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
1013         }
1014         switch (length) {
1015                 case JMP_SHORTEST:
1016                 case JMP_SHORT:
1017                         g(add_relocation(ctx, JMP_SHORT, 1, NULL));
1018                         cgen_four(mc);
1019                         return true;
1020                 case JMP_LONG:
1021                         cgen_four((mc ^ ARM64_CBZ_CBNZ) | 0x40);
1022                         g(add_relocation(ctx, JMP_LONG, 1, NULL));
1023                         cgen_four(ARM64_B);
1024                         return true;
1025                 default:
1026                         internal(file_line, "cgen_jmp_reg: invalid length %u", length);
1027                         return false;
1028         }
1031 static bool attr_w cgen_jmp_reg_bit(struct codegen_context *ctx, unsigned bit, bool jnz, unsigned length)
1033         uint32_t mc = ARM64_TB;
1034         mc |= ARM64_TB_TBNZ * (uint32_t)jnz;
1035         mc |= cget_one(ctx);
1036         mc |= (uint32_t)(bit & 31) << 19;
1037         mc |= (uint32_t)(bit >> 5 << 31);
1038         switch (length) {
1039                 case JMP_SHORTEST:
1040                         g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
1041                         cgen_four(mc);
1042                         return true;
1043                 case JMP_SHORT:
1044                 case JMP_LONG:
1045                         cgen_four((mc ^ ARM64_TB_TBNZ) | 0x40);
1046                         g(add_relocation(ctx, JMP_LONG, 1, NULL));
1047                         cgen_four(ARM64_B);
1048                         return true;
1049                 default:
1050                         internal(file_line, "cgen_jmp_reg_bit: invalid length %u", length);
1051                         return false;
1052         }
1055 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1057         uint32_t mc;
1058         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
1059         switch (reloc->length) {
1060                 case JMP_SHORTEST:
1061                         if (unlikely(offs < -0x00002000) || unlikely(offs >= 0x00002000))
1062                                 return false;
1063                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1064                         mc &= 0xfff8001fU;
1065                         mc |= ((uint32_t)offs << 5) & 0x0007ffe0;
1066                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1067                         return true;
1068                 case JMP_SHORT:
1069                         if (unlikely(offs < -0x00040000) || unlikely(offs >= 0x00040000))
1070                                 return false;
1071                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1072                         mc &= 0xff00001fU;
1073                         mc |= ((uint32_t)offs << 5) & 0x00ffffe0;
1074                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1075                         return true;
1076                 case JMP_LONG:
1077                         if (unlikely(offs < -0x02000000) || unlikely(offs >= 0x02000000))
1078                                 return false;
1079                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1080                         mc &= 0xfc000000U;
1081                         mc |= offs & 0x03ffffffU;
1082                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1083                         return true;
1084                 default:
1085                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1086         }
1087         return false;
1090 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1092         uint32_t reg;
1093         /*debug("insn: %08x (%s)", insn, da(ctx->fn,function)->function_name);*/
1094         switch (insn_opcode(insn)) {
1095                 case INSN_ENTRY:
1096                         g(cgen_entry(ctx));
1097                         return true;
1098                 case INSN_LABEL:
1099                         g(cgen_label(ctx));
1100                         return true;
1101                 case INSN_RET:
1102                         cgen_four(ARM64_RET);
1103                         return true;
1104                 case INSN_CALL_INDIRECT:
1105                         reg = cget_one(ctx);
1106                         cgen_four(ARM64_BLR | (reg << 5));
1107                         return true;
1108                 case INSN_MOV:
1109                         g(cgen_mov(ctx, insn_op_size(insn), false));
1110                         return true;
1111                 case INSN_MOVSX:
1112                         g(cgen_mov(ctx, insn_op_size(insn), true));
1113                         return true;
1114                 case INSN_CMP:
1115                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1116                                 goto invalid_insn;
1117                         g(cgen_cmp(ctx, insn_op_size(insn), false));
1118                         return true;
1119                 case INSN_CMN:
1120                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1121                                 goto invalid_insn;
1122                         g(cgen_cmp(ctx, insn_op_size(insn), true));
1123                         return true;
1124                 case INSN_TEST:
1125                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1126                                 goto invalid_insn;
1127                         g(cgen_test(ctx, insn_op_size(insn)));
1128                         return true;
1129                 case INSN_ALU:
1130                 case INSN_ALU_FLAGS:
1131                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1132                                 goto invalid_insn;
1133                         g(cgen_alu(ctx, insn_op_size(insn), insn_writes_flags(insn), insn_aux(insn)));
1134                         return true;
1135                 case INSN_ALU1:
1136                 case INSN_ALU1_FLAGS:
1137                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1138                                 goto invalid_insn;
1139                         g(cgen_alu1(ctx, insn_op_size(insn), insn_writes_flags(insn), insn_aux(insn)));
1140                         return true;
1141                 case INSN_ROT:
1142                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1143                                 goto invalid_insn;
1144                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
1145                         return true;
1146                 case INSN_MADD:
1147                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1148                                 goto invalid_insn;
1149                         g(cgen_madd(ctx, insn_op_size(insn), insn_aux(insn)));
1150                         return true;
1151                 case INSN_SET_COND:
1152                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1153                                 goto invalid_insn;
1154                         g(cgen_set_cond(ctx, insn_op_size(insn), insn_aux(insn)));
1155                         return true;
1156                 case INSN_CMOV:
1157                 case INSN_CMOV_XCC:
1158                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1159                                 goto invalid_insn;
1160                         g(cgen_csel(ctx, INSN_CSEL_SEL, insn_op_size(insn), insn_aux(insn)));
1161                         return true;
1162                 case INSN_CSEL_SEL:
1163                 case INSN_CSEL_INC:
1164                 case INSN_CSEL_INV:
1165                 case INSN_CSEL_NEG:
1166                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1167                                 goto invalid_insn;
1168                         g(cgen_csel(ctx, insn_opcode(insn), insn_op_size(insn), insn_aux(insn)));
1169                         return true;
1170                 case INSN_STP:
1171                 case INSN_LDP:
1172                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1173                                 goto invalid_insn;
1174                         g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP, insn_op_size(insn)));
1175                         return true;
1176                 case INSN_MOV_MASK:
1177                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
1178                                 goto invalid_insn;
1179                         g(cgen_mov_mask(ctx, insn_aux(insn)));
1180                         return true;
1181                 case INSN_FP_CMP:
1182                         g(cgen_fp_cmp(ctx, insn_op_size(insn)));
1183                         return true;
1184                 case INSN_FP_ALU:
1185                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1186                         return true;
1187                 case INSN_FP_ALU1:
1188                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1189                         return true;
1190                 case INSN_FP_TO_INT32:
1191                 case INSN_FP_TO_INT64:
1192                         g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1193                         return true;
1194                 case INSN_FP_FROM_INT32:
1195                 case INSN_FP_FROM_INT64:
1196                         g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1197                         return true;
1198                 case INSN_FP_CVT:
1199                         g(cgen_fp_cvt(ctx, insn_op_size(insn), insn_aux(insn)));
1200                         return true;
1201                 case INSN_JMP:
1202                         g(add_relocation(ctx, JMP_LONG, 0, NULL));
1203                         cgen_four(ARM64_B);
1204                         return true;
1205                 case INSN_JMP_COND:
1206                         g(cgen_jmp_cond(ctx, insn_aux(insn), insn_jump_size(insn)));
1207                         return true;
1208                 case INSN_JMP_REG:
1209                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1210                                 goto invalid_insn;
1211                         g(cgen_jmp_reg(ctx, insn_op_size(insn), insn_aux(insn), insn_jump_size(insn)));
1212                         return true;
1213                 case INSN_JMP_REG_BIT:
1214                         g(cgen_jmp_reg_bit(ctx, insn_aux(insn) & 63, insn_aux(insn) >> 6, insn_jump_size(insn)));
1215                         return true;
1216                 case INSN_JMP_INDIRECT:
1217                         reg = cget_one(ctx);
1218                         cgen_four(ARM64_BR | (reg << 5));
1219                         return true;
1220                 invalid_insn:
1221                 default:
1222                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
1223                         return false;
1224         }