codegen: introduce gen_mov and use it instead of explicit coding
[ajla.git] / c2-ia64.inc
blobab648a85846eb35c8e68b009f5426d1faef0fa94
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 IA64_A_ALU              0x10000000000ULL
20 #define  IA64_A_ALU_ADD         0x00000000000ULL
21 #define  IA64_A_ALU_SUB         0x00028000000ULL
22 #define  IA64_A_ALU_AND         0x00060000000ULL
23 #define  IA64_A_ALU_ANDCM       0x00068000000ULL
24 #define  IA64_A_ALU_OR          0x00070000000ULL
25 #define  IA64_A_ALU_XOR         0x00078000000ULL
26 #define IA64_A_SHLADD           0x10080000000ULL
27 #define IA64_A_ADD_IMM14        0x10800000000ULL
28 #define IA64_A_ALU_IMM8         0x10000000000ULL
29 #define  IA64_A_ALU_IMM8_SUB    0x00128000000ULL
30 #define  IA64_A_ALU_IMM8_AND    0x00160000000ULL
31 #define  IA64_A_ALU_IMM8_ANDCM  0x00168000000ULL
32 #define  IA64_A_ALU_IMM8_OR     0x00170000000ULL
33 #define  IA64_A_ALU_IMM8_XOR    0x00178000000ULL
34 #define IA64_A_ADD_IMM22        0x12000000000ULL
35 #define IA64_A_CMP_LT           0x18000000000ULL
36 #define IA64_A_CMP_LT_IMM8      0x18800000000ULL
37 #define IA64_A_CMP_LTU          0x1a000000000ULL
38 #define IA64_A_CMP_LTU_IMM8     0x1a800000000ULL
39 #define IA64_A_CMP_EQ           0x1c000000000ULL
40 #define IA64_A_CMP_EQ_IMM8      0x1c800000000ULL
41 #define  IA64_A_CMP4            0x00400000000ULL
43 #define IA64_I_ZXT1             0x00080000000ULL
44 #define IA64_I_ZXT2             0x00088000000ULL
45 #define IA64_I_ZXT4             0x00090000000ULL
46 #define IA64_I_SXT1             0x000a0000000ULL
47 #define IA64_I_SXT2             0x000a8000000ULL
48 #define IA64_I_SXT4             0x000b0000000ULL
49 #define IA64_I_NOP              0x00008000000ULL
50 #define IA64_I_MOV_TO_AR        0x00150000000ULL
51 #define IA64_I_MOV_TO_AR_PFS    0x00004000000ULL
52 #define IA64_I_MOVE_FROM_BR     0x00188000000ULL
53 #define IA64_I_MOVE_TO_BR       0x00e00000000ULL
54 #define IA64_I_DEP              0x08000000000ULL
55 #define IA64_I_TBIT             0x0a000000000ULL
56 #define IA64_I_EXTR_U           0x0a400000000ULL
57 #define IA64_I_EXTR             0x0a400002000ULL
58 #define IA64_I_DEP_Z            0x0a600000000ULL
59 #define IA64_I_DEP_Z_IMM        0x0a604000000ULL
60 #define IA64_I_DEP_IMM          0x0ae00000000ULL
61 #define IA64_I_POPCNT           0x0e690000000ULL
62 #define IA64_I_MUX1_REV         0x0eca0b00000ULL
63 #define IA64_I_SHR_U            0x0f200000000ULL
64 #define IA64_I_SHR              0x0f220000000ULL
65 #define IA64_I_SHL              0x0f240000000ULL
67 #define IA64_M_NOP              0x00008000000ULL
68 #define IA64_M_ALLOC            0x02c00000000ULL
69 #define IA64_M_LD1              0x08000000000ULL
70 #define IA64_M_LD2              0x08040000000ULL
71 #define IA64_M_LD4              0x08080000000ULL
72 #define IA64_M_LD8              0x080c0000000ULL
73 #define IA64_M_GETF_SIG         0x08708000000ULL
74 #define IA64_M_ST1              0x08c00000000ULL
75 #define IA64_M_ST2              0x08c40000000ULL
76 #define IA64_M_ST4              0x08c80000000ULL
77 #define IA64_M_ST8              0x08cc0000000ULL
78 #define IA64_M_LDFE             0x0c000000000ULL
79 #define IA64_M_LDF8             0x0c040000000ULL
80 #define IA64_M_LDFS             0x0c080000000ULL
81 #define IA64_M_LDFD             0x0c0c0000000ULL
82 #define IA64_M_SETF_SIG         0x0c708000000ULL
83 #define IA64_M_STFE             0x0cc00000000ULL
84 #define IA64_M_STF8             0x0cc40000000ULL
85 #define IA64_M_STFS             0x0cc80000000ULL
86 #define IA64_M_STFD             0x0ccc0000000ULL
88 #define IA64_B_BR_JMP_INDIRECT  0x00100001000ULL
89 #define IA64_B_BR_RET           0x00108801100ULL
90 #define IA64_B_BR_CALL_INDIRECT 0x02100001000ULL
91 #define IA64_B_NOP              0x04000000000ULL
92 #define IA64_B_BR21             0x08000001000ULL
93 #define IA64_BR_DPNT            0x00600000000ULL
95 #define IA64_F_NOP              0x00008000000ULL
96 #define IA64_F_FMERGE_S         0x00080000000ULL
97 #define IA64_F_FMERGE_NS        0x00088000000ULL
98 #define IA64_F_FMERGE_SE        0x00090000000ULL
99 #define IA64_F_FCVT_FX_TRUNC    0x000d0000000ULL
100 #define IA64_F_FCVT_XF          0x000e0000000ULL
101 #define IA64_F_FCMP             0x08000000000ULL
102 #define  IA64_F_FCMP_EQ         0x00000000000ULL
103 #define  IA64_F_FCMP_LE         0x00200000000ULL
104 #define  IA64_F_FCMP_LT         0x01000000000ULL
105 #define  IA64_F_FCMP_UNORD      0x01200000000ULL
106 #define IA64_F_FMA              0x10000000000ULL
107 #define IA64_F_FMS              0x14000000000ULL
108 #define IA64_F_FNMA             0x18000000000ULL
109 #define  IA64_F_FMA_E           0x00000000000ULL
110 #define  IA64_F_FMA_S           0x01000000000ULL
111 #define  IA64_F_FMA_D           0x02000000000ULL
112 #define  IA64_F_FMA_PS          0x03000000000ULL
114 #define IA64_L_NOP              0x00000000000ULL
116 #define IA64_X_NOP              0x00008000000ULL
117 #define IA64_X_BRL              0x18000001000ULL
118 #define IA64_X_MOVL             0x0c000000000ULL
120 #define UNIT_ANY                0x0f
121 #define UNIT_A                  0x03
122 #define UNIT_I                  0x01
123 #define UNIT_M                  0x02
124 #define UNIT_B                  0x04
125 #define UNIT_F                  0x08
126 #define UNIT_L                  0x10
127 #define UNIT_X                  0x20
129 #define STOP_01                 0x01000000U
130 #define STOP_12                 0x02000000U
131 #define STOP_23                 0x04000000U
133 static const uint32_t templates[32] = {
134         UNIT_M | UNIT_I << 8 | UNIT_I << 16,
135         UNIT_M | UNIT_I << 8 | UNIT_I << 16 | STOP_23,
136         UNIT_M | UNIT_I << 8 | UNIT_I << 16 | STOP_12,
137         UNIT_M | UNIT_I << 8 | UNIT_I << 16 | STOP_12 | STOP_23,
138         UNIT_M | UNIT_L << 8 | UNIT_X << 16,
139         UNIT_M | UNIT_L << 8 | UNIT_X << 16 | STOP_23,
140         0,
141         0,
142         UNIT_M | UNIT_M << 8 | UNIT_I << 16,
143         UNIT_M | UNIT_M << 8 | UNIT_I << 16 | STOP_23,
144         UNIT_M | UNIT_M << 8 | UNIT_I << 16 | STOP_01,
145         UNIT_M | UNIT_M << 8 | UNIT_I << 16 | STOP_01 | STOP_23,
146         UNIT_M | UNIT_F << 8 | UNIT_I << 16,
147         UNIT_M | UNIT_F << 8 | UNIT_I << 16 | STOP_23,
148         UNIT_M | UNIT_M << 8 | UNIT_F << 16,
149         UNIT_M | UNIT_M << 8 | UNIT_F << 16 | STOP_23,
150         UNIT_M | UNIT_I << 8 | UNIT_B << 16,
151         UNIT_M | UNIT_I << 8 | UNIT_B << 16 | STOP_23,
152         UNIT_M | UNIT_B << 8 | UNIT_B << 16,
153         UNIT_M | UNIT_B << 8 | UNIT_B << 16 | STOP_23,
154         0,
155         0,
156         UNIT_B | UNIT_B << 8 | UNIT_B << 16,
157         UNIT_B | UNIT_B << 8 | UNIT_B << 16 | STOP_23,
158         UNIT_M | UNIT_M << 8 | UNIT_B << 16,
159         UNIT_M | UNIT_M << 8 | UNIT_B << 16 | STOP_23,
160         0,
161         0,
162         UNIT_M | UNIT_F << 8 | UNIT_B << 16,
163         UNIT_M | UNIT_F << 8 | UNIT_B << 16 | STOP_23,
164         0,
165         0,
168 #define ACCESS_MEMORY           0xfe
169 #define ACCESS_NOTHING          0xff
171 static void new_bundle(struct codegen_context *ctx)
173         unsigned i;
174         for (i = 0; i < 3; i++) {
175                 ctx->a.insns[i] = -1ULL;
176                 ctx->a.insn_units[i] = 0xff;
177                 ctx->a.insn_stops[i] = false;
178         }
181 static void clear_wr_mask(struct codegen_context *ctx)
183         memset(&ctx->a.wr_mask, 0, sizeof ctx->a.wr_mask);
186 static void init_arch_context(struct codegen_context *ctx)
188         new_bundle(ctx);
189         clear_wr_mask(ctx);
192 static bool test_mask(uint64_t mask[4], uint8_t bit)
194         return mask[bit >> 6] & 1ULL << (bit & 63);
197 static void set_mask(uint64_t mask[4], uint8_t bit)
199         if (bit == ACCESS_NOTHING)
200                 return;
201         mask[bit >> 6] |= 1ULL << (bit & 63);
204 static uint32_t get_possible_templates(struct codegen_context *ctx)
206         unsigned i, j;
207         uint32_t result = 0;
208         for (i = 0; i < 32; i++) {
209                 uint32_t tmpl = templates[i];
210                 for (j = 0; j < 3; j++) {
211                         uint8_t insn_unit = ctx->a.insn_units[j];
212                         uint8_t tmpl_unit = tmpl >> (j * 8) & 0xff;
213                         if (!(tmpl_unit & insn_unit)) {
214                                 goto failed_match;
215                         }
216                         if (ctx->a.insn_stops[j] != (tmpl >> (24 + j) & 1)) {
217                                 goto failed_match;
218                         }
219                 }
220                 result |= 1U << i;
221 failed_match:;
222         }
223         return result;
226 static uint64_t get_nop(unsigned unit)
228         switch (unit) {
229                 case UNIT_I:    return IA64_I_NOP;
230                 case UNIT_M:    return IA64_M_NOP;
231                 case UNIT_B:    return IA64_B_NOP;
232                 case UNIT_F:    return IA64_F_NOP;
233                 case UNIT_L:    return IA64_L_NOP;
234                 case UNIT_X:    return IA64_X_NOP;
235                 default:        internal(file_line, "get_nop: invalid unit %x", unit);
236                                 return 0;
237         }
240 static unsigned get_free_slot(struct codegen_context *ctx)
242         unsigned slot = 3;
243         while (slot > 0 && ctx->a.insns[slot - 1] == -1ULL)
244                 slot--;
245         return slot;
248 static bool attr_w ia64_purge_bundle(struct codegen_context *ctx)
250         uint32_t tmpls;
251         unsigned tmpl, i;
252         uint64_t low, high;
253         if (!get_free_slot(ctx))
254                 return true;
255         tmpls = get_possible_templates(ctx);
256         if (unlikely(!tmpls))
257                 internal(file_line, "ia64_purge_bundle: no possible templates");
258         tmpl = low_bit(tmpls);
259         for (i = 0; i < 3; i++) {
260                 if (ctx->a.insns[i] == -1ULL) {
261                         ctx->a.insns[i] = get_nop(templates[tmpl] >> (i * 8) & 0xff);
262                         ctx->a.insn_units[i] = templates[tmpl] >> (i * 8) & 0xff;
263                 }
264         }
265         low = tmpl | ctx->a.insns[0] << 5 | ctx->a.insns[1] << 46;
266         high = ctx->a.insns[1] >> 18 | ctx->a.insns[2] << 23;
267         cgen_eight(low);
268         cgen_eight(high);
269         new_bundle(ctx);
270         return true;
273 static bool ia64_fill_bundle(struct codegen_context *ctx)
275         uint32_t tmpls;
276         unsigned tmpl, i;
277         if (!get_free_slot(ctx))
278                 return false;
279         tmpls = get_possible_templates(ctx);
280         if (unlikely(!tmpls))
281                 internal(file_line, "ia64_fill_bundle: no possible templates");
282         tmpl = low_bit(tmpls);
283         for (i = 0; i < 3; i++) {
284                 if (ctx->a.insns[i] == -1ULL) {
285                         ctx->a.insns[i] = get_nop(templates[tmpl] >> (i * 8) & 0xff);
286                         ctx->a.insn_units[i] = templates[tmpl] >> (i * 8) & 0xff;
287                 }
288         }
289         return true;
292 static bool attr_w ia64_insn(struct codegen_context *ctx, uint8_t unit, uint64_t mc, uint8_t wr1, uint8_t wr2, uint8_t rd1, uint8_t rd2, uint8_t rd3)
294         unsigned slot = get_free_slot(ctx);
295         bool need_stop = false;
296         need_stop |= test_mask(ctx->a.wr_mask, wr1);
297         need_stop |= test_mask(ctx->a.wr_mask, wr2);
298         need_stop |= test_mask(ctx->a.wr_mask, rd1);
299         need_stop |= test_mask(ctx->a.wr_mask, rd2);
300         need_stop |= test_mask(ctx->a.wr_mask, rd3);
301         /*debug("ia64_insn: %x, %lx, %d, %u", unit, mc, need_stop, slot);*/
302         if (slot > 0) {
303                 if (need_stop) {
304 try_stop_in_next_slot:
305                         ctx->a.insn_stops[slot - 1] = need_stop;
306                         if (!get_possible_templates(ctx)) {
307                                 ctx->a.insn_stops[slot - 1] = false;
308                                 slot++;
309                                 if (unlikely(slot > 3))
310                                         internal(file_line, "ia64_insn: can't set stop at the end of the bundle");
311                                 goto try_stop_in_next_slot;
312                         }
313                 }
314                 if (slot == 3) {
315                         g(ia64_purge_bundle(ctx));
316                         slot = 0;
317                 }
318                 if (need_stop) {
319                         clear_wr_mask(ctx);
320                 }
321         }
322 try_next_slot:
323         ctx->a.insn_units[slot] = unit;
324         if (!get_possible_templates(ctx)) {
325                 ctx->a.insn_units[slot] = 0xff;
326                 slot++;
327                 if (unlikely(slot == 3)) {
328                         g(ia64_purge_bundle(ctx));
329                         slot = 0;
330                 }
331                 goto try_next_slot;
332         }
333         ctx->a.insns[slot] = mc;
334         set_mask(ctx->a.wr_mask, wr1);
335         set_mask(ctx->a.wr_mask, wr2);
336         return true;
339 static bool attr_w cgen_ia64_ret(struct codegen_context *ctx)
341         uint64_t mc;
342         mc = IA64_B_BR_RET;
343         mc |= bits_b(B_0) << 13;
344         g(ia64_insn(ctx, UNIT_B, mc, ACCESS_MEMORY, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
345         mc = IA64_B_NOP;
346         g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_MEMORY, ACCESS_NOTHING, ACCESS_NOTHING));
347         return true;
350 static bool attr_w cgen_ia64_alloc(struct codegen_context *ctx)
352         uint64_t mc;
353         uint8_t *arg1 = ctx->code_position;
354         uint8_t *arg2 = arg1 + arg_size(*arg1);
355         uint8_t *arg3 = arg2 + arg_size(*arg2);
356         ctx->code_position = arg3 + arg_size(*arg3);
357         ia64_fill_bundle(ctx);
358         mc = IA64_M_ALLOC;
359         mc |= bits_gr(arg1[0]) << 6;
360         mc |= get_imm(&arg2[1]) << 13;
361         mc |= get_imm(&arg3[1]) << 20;
362         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
363         return true;
366 static bool attr_w cgen_ia64_dealloc(struct codegen_context *ctx)
368         uint64_t mc;
369         uint8_t *arg1 = ctx->code_position;
370         ctx->code_position = arg1 + arg_size(*arg1);
371         mc = IA64_I_MOV_TO_AR | IA64_I_MOV_TO_AR_PFS;
372         mc |= bits_gr(arg1[0]) << 13;
373         g(ia64_insn(ctx, UNIT_I, mc, ACCESS_NOTHING, ACCESS_NOTHING, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING));
374         return true;
377 static bool attr_w cgen_call_indirect(struct codegen_context *ctx)
379         uint64_t mc;
380         unsigned reg = cget_one(ctx);
381         mc = IA64_B_BR_CALL_INDIRECT;
382         mc |= bits_b(B_0) << 6;
383         mc |= bits_b(reg) << 13;
384         g(ia64_insn(ctx, UNIT_B, mc, B_0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
385         return true;
388 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
390         uint64_t mc;
391         int64_t imm;
392         uint8_t z = R_ZERO;
393         uint8_t *arg1 = ctx->code_position;
394         uint8_t *arg2 = arg1 + arg_size(*arg1);
395         ctx->code_position = arg2 + arg_size(*arg2);
397         if (reg_is_gr(arg1[0])) {
398                 if (reg_is_gr(arg2[0])) {
399                         switch (size) {
400                                 case OP_SIZE_1:
401                                         mc = IA64_I_ZXT1;
402                                         break;
403                                 case OP_SIZE_2:
404                                         mc = IA64_I_ZXT2;
405                                         break;
406                                 case OP_SIZE_4:
407                                         mc = IA64_I_ZXT4;
408                                         break;
409                                 case OP_SIZE_NATIVE:
410                                         mc = IA64_A_ADD_IMM14;
411                                         mc |= bits_gr(arg1[0]) << 6;
412                                         mc |= bits_gr(arg2[0]) << 20;
413                                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
414                                         return true;
415                                 default:
416                                         goto invalid;
417                         }
418                         mc |= bits_gr(arg1[0]) << 6;
419                         mc |= bits_gr(arg2[0]) << 20;
420                         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
421                         return true;
422                 }
423                 if (reg_is_fp(arg2[0])) {
424                         mc = IA64_M_GETF_SIG;
425                         mc |= bits_gr(arg1[0]) << 6;
426                         mc |= bits_fp(arg2[0]) << 13;
427                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
428                         return true;
429                 }
430                 if (reg_is_b(arg2[0])) {
431                         mc = IA64_I_MOVE_FROM_BR;
432                         mc |= bits_gr(arg1[0]) << 6;
433                         mc |= bits_b(arg2[0]) << 13;
434                         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
435                         return true;
436                 }
437                 if (reg_is_p(arg2[0])) {
438                         mc = IA64_A_ADD_IMM14;
439                         mc |= bits_gr(arg1[0]) << 6;
440                         mc |= (uint64_t)1 << 13;
441                         mc |= bits_p(arg2[0]);
442                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
444                         mc = IA64_A_ADD_IMM14;
445                         mc |= bits_gr(arg1[0]) << 6;
446                         mc |= bits_p(arg2[0] ^ 1);
447                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
449                         return true;
450                 }
451                 if (arg2[0] == ARG_ADDRESS_1) {
452                         imm = get_imm(&arg2[2]);
453                         if (unlikely(imm != 0))
454                                 goto invalid;
455                         switch (size) {
456                                 case OP_SIZE_1: mc = IA64_M_LD1; break;
457                                 case OP_SIZE_2: mc = IA64_M_LD2; break;
458                                 case OP_SIZE_4: mc = IA64_M_LD4; break;
459                                 case OP_SIZE_8: mc = IA64_M_LD8; break;
460                                 default:        goto invalid;
461                         }
462                         mc |= bits_gr(arg1[0]) << 6;
463                         mc |= bits_gr(arg2[1]) << 20;
464                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_MEMORY, ACCESS_NOTHING));
465                         return true;
466                 }
467                 if (arg2[0] == ARG_IMM) {
468                         imm = get_imm(&arg2[1]);
469                         if (imm >= -0x200000 && imm < 0x200000) {
470                                 mc = IA64_A_ADD_IMM22;
471                                 mc |= bits_gr(arg1[0]) << 6;
472                                 mc |= (imm & 0x7f) << 13;
473                                 mc |= ((uint64_t)imm >> 7 & 0x1ff) << 27;
474                                 mc |= ((uint64_t)imm >> 16 & 0x1f) << 22;
475                                 mc |= ((uint64_t)imm >> 21 & 0x1) << 36;
476                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
477                                 return true;
478                         } else {
479                                 mc = (imm & 0x7fffffffffc00000ULL) >> 22;
480                                 g(ia64_insn(ctx, UNIT_L, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
481                                 mc = IA64_X_MOVL;
482                                 mc |= bits_gr(arg1[0]) << 6;
483                                 mc |= (imm & 0x7f) << 13;
484                                 mc |= ((uint64_t)imm >> 7 & 0x1ff) << 27;
485                                 mc |= ((uint64_t)imm >> 16 & 0x1f) << 22;
486                                 mc |= ((uint64_t)imm >> 21 & 0x1) << 21;
487                                 mc |= ((uint64_t)imm >> 63) << 36;
488                                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
489                                 return true;
490                         }
491                 }
492         }
493         if (reg_is_fp(arg1[0])) {
494                 if (reg_is_gr(arg2[0])) {
495                         mc = IA64_M_SETF_SIG;
496                         mc |= bits_fp(arg1[0]) << 6;
497                         mc |= bits_gr(arg2[0]) << 13;
498                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_NOTHING, ACCESS_NOTHING));
499                         return true;
500                 }
501                 if (arg2[0] == ARG_ADDRESS_1) {
502                         imm = get_imm(&arg2[2]);
503                         if (unlikely(imm != 0))
504                                 goto invalid;
505                         switch (size) {
506                                 case OP_SIZE_4: mc = IA64_M_LDFS; break;
507                                 case OP_SIZE_8: mc = IA64_M_LDFD; break;
508                                 case OP_SIZE_10:mc = IA64_M_LDFE; break;
509                                 default:        goto invalid;
510                         }
511                         mc |= bits_fp(arg1[0]) << 6;
512                         mc |= bits_gr(arg2[1]) << 20;
513                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_MEMORY, ACCESS_NOTHING));
514                         return true;
515                 }
516         }
517         if (reg_is_b(arg1[0])) {
518                 if (reg_is_gr(arg2[0])) {
519                         mc = IA64_I_MOVE_TO_BR;
520                         mc |= bits_gr(arg2[0]) << 13;
521                         mc |= bits_b(arg1[0]) << 6;
522                         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
523                         return true;
524                 }
525         }
526         if (arg1[0] == ARG_ADDRESS_1) {
527                 imm = get_imm(&arg1[2]);
528                 if (unlikely(imm != 0))
529                         goto invalid;
530                 if (arg2[0] == ARG_IMM) {
531                         imm = get_imm(&arg2[1]);
532                         if (unlikely(imm != 0))
533                                 goto invalid;
534                         arg2 = &z;
535                 }
536                 if (reg_is_gr(arg2[0])) {
537                         switch (size) {
538                                 case OP_SIZE_1: mc = IA64_M_ST1; break;
539                                 case OP_SIZE_2: mc = IA64_M_ST2; break;
540                                 case OP_SIZE_4: mc = IA64_M_ST4; break;
541                                 case OP_SIZE_8: mc = IA64_M_ST8; break;
542                                 default:        goto invalid;
543                         }
544                         mc |= bits_gr(arg2[0]) << 13;
545                         mc |= bits_gr(arg1[1]) << 20;
546                         g(ia64_insn(ctx, UNIT_M, mc, ACCESS_MEMORY, ACCESS_NOTHING, arg1[1], arg2[0], ACCESS_NOTHING));
547                         return true;
548                 }
549                 if (reg_is_fp(arg2[0])) {
550                         switch (size) {
551                                 case OP_SIZE_4: mc = IA64_M_STFS; break;
552                                 case OP_SIZE_8: mc = IA64_M_STFD; break;
553                                 case OP_SIZE_10:mc = IA64_M_STFE; break;
554                                 default:        goto invalid;
555                         }
556                         mc |= bits_fp(arg2[0]) << 13;
557                         mc |= bits_gr(arg1[1]) << 20;
558                         g(ia64_insn(ctx, UNIT_M, mc, ACCESS_MEMORY, ACCESS_NOTHING, arg1[1], arg2[0], ACCESS_NOTHING));
559                         return true;
560                 }
561         }
563 invalid:
564         internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u", arg1[0], arg2[0], size);
565         return false;
568 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
570         uint64_t mc;
571         uint8_t *arg1 = ctx->code_position;
572         uint8_t *arg2 = arg1 + arg_size(*arg1);
573         ctx->code_position = arg2 + arg_size(*arg2);
575         if (likely(reg_is_gr(arg1[0])) && likely(reg_is_gr(arg2[0]))) {
576                 switch (size) {
577                         case OP_SIZE_1:
578                                 mc = IA64_I_SXT1;
579                                 break;
580                         case OP_SIZE_2:
581                                 mc = IA64_I_SXT2;
582                                 break;
583                         case OP_SIZE_4:
584                                 mc = IA64_I_SXT4;
585                                 break;
586                         case OP_SIZE_NATIVE:
587                                 mc = IA64_A_ADD_IMM14;
588                                 mc |= bits_gr(arg1[0]) << 6;
589                                 mc |= bits_gr(arg2[0]) << 20;
590                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
591                                 return true;
592                         default:
593                                 goto invalid;
594                 }
595                 mc |= bits_gr(arg1[0]) << 6;
596                 mc |= bits_gr(arg2[0]) << 20;
597                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
598                 return true;
599         }
601 invalid:
602         internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u", arg1[0], arg2[0], size);
603         return false;
606 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned cond)
608         uint64_t mc;
609         unsigned pred;
610         bool swap_preds = false, swap_regs = false;
611         uint8_t z = R_ZERO;
612         uint8_t *arg1 = ctx->code_position;
613         uint8_t *arg2 = arg1 + arg_size(*arg1);
614         uint8_t *arg3 = arg2 + arg_size(*arg2);
615         ctx->code_position = arg3 + arg_size(*arg3);
617         if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
618                 goto invalid;
620         pred = arg1[0];
622         if (arg3[0] == ARG_IMM) {
623                 int64_t imm = get_imm(&arg3[1]);
624                 if (likely(!imm)) {
625                         arg3 = &z;
626                         goto cmp_3reg;
627                 }
628                 if (unlikely(imm <= -0x80) || unlikely(imm >= 0x80))
629                         goto invalid;
630                 switch (cond) {
631                         case COND_AE:   mc = IA64_A_CMP_LTU_IMM8; imm--; break;
632                         case COND_B:    mc = IA64_A_CMP_LTU_IMM8; imm--; swap_preds = true; break;
633                         case COND_E:    mc = IA64_A_CMP_EQ_IMM8; break;
634                         case COND_NE:   mc = IA64_A_CMP_EQ_IMM8; swap_preds = true; break;
635                         case COND_BE:   mc = IA64_A_CMP_LTU_IMM8; swap_preds = true; break;
636                         case COND_A:    mc = IA64_A_CMP_LTU_IMM8; break;
637                         case COND_L:    mc = IA64_A_CMP_LT_IMM8; imm--; swap_preds = true; break;
638                         case COND_GE:   mc = IA64_A_CMP_LT_IMM8; imm--; break;
639                         case COND_LE:   mc = IA64_A_CMP_LT_IMM8; swap_preds = true; break;
640                         case COND_G:    mc = IA64_A_CMP_LT_IMM8; break;
641                         default:        goto invalid;
642                 }
644                 if (swap_preds)
645                         pred ^= 1;
647                 if (op_size == OP_SIZE_4)
648                         mc |= IA64_A_CMP4;
650                 mc |= (imm & 0x7f) << 13;
651                 mc |= ((uint64_t)imm >> 7 & 1) << 36;
652                 mc |= bits_gr(arg2[0]) << 20;
653                 mc |= bits_p(pred) << 6;
654                 mc |= bits_p(pred ^ 1) << 27;
655                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], arg3[0], ACCESS_NOTHING));
656                 return true;
657         }
659         if (!reg_is_gr(arg3[0]))
660                 goto invalid;
662 cmp_3reg:
663         switch (cond) {
664                 case COND_B:    mc = IA64_A_CMP_LTU; break;
665                 case COND_AE:   mc = IA64_A_CMP_LTU; swap_preds = true; break;
666                 case COND_E:    mc = IA64_A_CMP_EQ; break;
667                 case COND_NE:   mc = IA64_A_CMP_EQ; swap_preds = true; break;
668                 case COND_BE:   mc = IA64_A_CMP_LTU; swap_regs = true; swap_preds = true; break;
669                 case COND_A:    mc = IA64_A_CMP_LTU; swap_regs = true; break;
670                 case COND_L:    mc = IA64_A_CMP_LT; break;
671                 case COND_GE:   mc = IA64_A_CMP_LT; swap_preds = true; break;
672                 case COND_LE:   mc = IA64_A_CMP_LT; swap_regs = true; swap_preds = true; break;
673                 case COND_G:    mc = IA64_A_CMP_LT; swap_regs = true; break;
674                 default:        goto invalid;
675         }
677         if (swap_regs) {
678                 uint8_t *argx = arg2;
679                 arg2 = arg3;
680                 arg3 = argx;
681         }
683         if (swap_preds)
684                 pred ^= 1;
686         if (op_size == OP_SIZE_4)
687                 mc |= IA64_A_CMP4;
689         mc |= bits_gr(arg2[0]) << 13;
690         mc |= bits_gr(arg3[0]) << 20;
691         mc |= bits_p(pred) << 6;
692         mc |= bits_p(pred ^ 1) << 27;
693         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], arg3[0], ACCESS_NOTHING));
694         return true;
696 invalid:
697         internal(file_line, "cgen_cmp_dest_reg: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
698         return false;
701 static bool attr_w cgen_test_dest_reg(struct codegen_context *ctx, unsigned bit, bool jnz)
703         uint64_t mc;
704         unsigned pred;
705         uint8_t *arg1 = ctx->code_position;
706         uint8_t *arg2 = arg1 + arg_size(*arg1);
707         ctx->code_position = arg2 + arg_size(*arg2);
709         if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
710                 goto invalid;
712         pred = arg1[0];
714         if (jnz)
715                 pred ^= 1;
717         mc = IA64_I_TBIT;
718         mc |= (uint64_t)bit << 14;
719         mc |= bits_gr(arg2[0]) << 20;
720         mc |= bits_p(pred) << 6;
721         mc |= bits_p(pred ^ 1) << 27;
722         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], arg1[0] ^ 1, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
723         return true;
725 invalid:
726         internal(file_line, "cgen_test_dest_reg: invalid arguments %02x, %02x", arg1[0], arg2[0]);
727         return false;
730 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned alu)
732         uint64_t mc;
733         uint8_t *arg1 = ctx->code_position;
734         uint8_t *arg2 = arg1 + arg_size(*arg1);
735         uint8_t *arg3 = arg2 + arg_size(*arg2);
736         ctx->code_position = arg3 + arg_size(*arg3);
738         if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
739                 uint8_t *arg_swp = arg3;
740                 arg3 = arg2;
741                 arg2 = arg_swp;
742         }
744         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
745                 goto invalid;
747 gr_gr_gr:
748         if (reg_is_gr(arg3[0])) {
749                 mc = IA64_A_ALU;
750                 switch (alu) {
751                         case ALU_ADD:   mc |= IA64_A_ALU_ADD; break;
752                         case ALU_SUB:   mc |= IA64_A_ALU_SUB; break;
753                         case ALU_AND:   mc |= IA64_A_ALU_AND; break;
754                         case ALU_ANDN:  mc |= IA64_A_ALU_ANDCM; break;
755                         case ALU_OR:    mc |= IA64_A_ALU_OR; break;
756                         case ALU_XOR:   mc |= IA64_A_ALU_XOR; break;
757                         default:        goto invalid;
758                 }
759                 mc |= bits_gr(arg1[0]) << 6;
760                 mc |= bits_gr(arg2[0]) << 13;
761                 mc |= bits_gr(arg3[0]) << 20;
762                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
763                 return true;
764         }
766         if (arg3[0] == ARG_SHIFTED_REGISTER && (arg3[1] & ARG_SHIFT_MODE) == ARG_SHIFT_LSL) {
767                 unsigned amount = arg3[1] & ARG_SHIFT_AMOUNT;
768                 if (!amount) {
769                         arg3 += 2;
770                         goto gr_gr_gr;
771                 }
772                 if (unlikely(amount > 4))
773                         goto invalid;
774                 mc = IA64_A_SHLADD;
775                 mc |= bits_gr(arg1[0]) << 6;
776                 mc |= bits_gr(arg3[2]) << 13;
777                 mc |= bits_gr(arg2[0]) << 20;
778                 mc |= (amount - 1) << 27;
779                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[2], ACCESS_NOTHING));
780                 return true;
781         }
783         if (arg3[0] == ARG_IMM) {
784                 int64_t imm = get_imm(&arg3[1]);
785                 if (alu == ALU_SUB) {
786                         imm = -(uint64_t)imm;
787                         alu = ALU_ADD;
788                 }
789                 if (alu == ALU_ADD) {
790                         if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
791                                 goto invalid;
792                         mc = IA64_A_ADD_IMM14;
793                         mc |= bits_gr(arg1[0]) << 6;
794                         mc |= bits_gr(arg2[0]) << 20;
795                         mc |= (imm & 0x7f) << 13;
796                         mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
797                         mc |= ((uint64_t)imm >> 13 & 1) << 36;
798                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
799                         return true;
800                 } else if (alu == ALU_AND || alu == ALU_OR || alu == ALU_XOR) {
801                         if (unlikely(imm < -0x80) || unlikely(imm >= 0x80))
802                                 goto invalid;
803                         mc = IA64_A_ALU_IMM8 | (alu == ALU_AND ? IA64_A_ALU_IMM8_AND : alu == ALU_OR ? IA64_A_ALU_IMM8_OR : IA64_A_ALU_IMM8_XOR);
804                         mc |= bits_gr(arg1[0]) << 6;
805                         mc |= bits_gr(arg2[0]) << 20;
806                         mc |= (imm & 0x7f) << 13;
807                         mc |= ((uint64_t)imm >> 7 & 1) << 36;
808                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
809                         return true;
810                 } else {
811                         goto invalid;
812                 }
813         }
815 invalid:
816         internal(file_line, "cgen_alu: invalid arguments %u, %02x, %02x, %02x", alu, arg1[0], arg2[0], arg3[0]);
817         return false;
820 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned alu)
822         uint64_t mc;
823         uint8_t *arg1 = ctx->code_position;
824         uint8_t *arg2 = arg1 + arg_size(*arg1);
825         ctx->code_position = arg2 + arg_size(*arg2);
827         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
828                 goto invalid;
831         switch (alu) {
832                 case ALU1_NOT:  mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_ANDCM;
833                                 mc |= bits_gr(arg1[0]) << 6;
834                                 mc |= bits_gr(arg2[0]) << 20;
835                                 mc |= 0x7fULL << 13;
836                                 mc |= 0x1ULL << 36;
837                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
838                                 return true;
839                 case ALU1_NEG:  mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_SUB;
840                                 mc |= bits_gr(arg1[0]) << 6;
841                                 mc |= bits_gr(arg2[0]) << 20;
842                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
843                                 return true;
844                 case ALU1_INC:  mc = IA64_A_ADD_IMM14;
845                                 mc |= bits_gr(arg1[0]) << 6;
846                                 mc |= bits_gr(arg2[0]) << 20;
847                                 mc |= 1ULL << 13;
848                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
849                                 return true;
850                 case ALU1_DEC:  mc = IA64_A_ADD_IMM14;
851                                 mc |= bits_gr(arg1[0]) << 6;
852                                 mc |= bits_gr(arg2[0]) << 20;
853                                 mc |= 0x7fULL << 13;
854                                 mc |= 0x3fULL << 27;
855                                 mc |= 0x1ULL << 36;
856                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
857                                 return true;
858                 case ALU1_BSWAP:mc = IA64_I_MUX1_REV;
859                                 mc |= bits_gr(arg1[0]) << 6;
860                                 mc |= bits_gr(arg1[1]) << 13;
861                                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
862                                 return true;
863                 case ALU1_POPCNT:
864                                 mc = IA64_I_POPCNT;
865                                 mc |= bits_gr(arg1[0]) << 6;
866                                 mc |= bits_gr(arg2[0]) << 20;
867                                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
868                                 return true;
869                 default:        goto invalid;
870         }
872 invalid:
873         internal(file_line, "cgen_alu1: invalid arguments %u, %02x, %02x", alu, arg1[0], arg2[0]);
874         return false;
878 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned rot)
880         uint64_t mc;
881         uint8_t *arg1 = ctx->code_position;
882         uint8_t *arg2 = arg1 + arg_size(*arg1);
883         uint8_t *arg3 = arg2 + arg_size(*arg2);
884         ctx->code_position = arg3 + arg_size(*arg3);
886         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
887                 goto invalid;
889         if (arg3[0] == ARG_IMM) {
890                 uint64_t pos = get_imm(&arg3[1]) & 63;
891                 uint64_t len = 64 - pos - 1;
892                 switch (rot) {
893                         case ROT_SHL:   mc = IA64_I_DEP_Z;
894                                         mc |= bits_gr(arg1[0]) << 6;
895                                         mc |= bits_gr(arg2[0]) << 13;
896                                         mc |= (pos ^ 0x3f) << 20;
897                                         mc |= len << 27;
898                                         break;
899                         case ROT_SHR:   mc = IA64_I_EXTR_U;
900                                         mc |= bits_gr(arg1[0]) << 6;
901                                         mc |= pos << 14;
902                                         mc |= bits_gr(arg2[0]) << 20;
903                                         mc |= len << 27;
904                                         break;
905                         case ROT_SAR:   mc = IA64_I_EXTR;
906                                         mc |= bits_gr(arg1[0]) << 6;
907                                         mc |= pos << 14;
908                                         mc |= bits_gr(arg2[0]) << 20;
909                                         mc |= len << 27;
910                                         break;
911                         default:        goto invalid;
912                 }
913                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
914                 return true;
915         }
917         if (reg_is_gr(arg3[0])) {
918                 switch (rot) {
919                         case ROT_SHL:   mc = IA64_I_SHL;
920                                         mc |= bits_gr(arg1[0]) << 6;
921                                         mc |= bits_gr(arg2[0]) << 13;
922                                         mc |= bits_gr(arg3[0]) << 20;
923                                         break;
924                         case ROT_SHR:   mc = IA64_I_SHR_U;
925                                         mc |= bits_gr(arg1[0]) << 6;
926                                         mc |= bits_gr(arg3[0]) << 13;
927                                         mc |= bits_gr(arg2[0]) << 20;
928                                         break;
929                         case ROT_SAR:   mc = IA64_I_SHR;
930                                         mc |= bits_gr(arg1[0]) << 6;
931                                         mc |= bits_gr(arg3[0]) << 13;
932                                         mc |= bits_gr(arg2[0]) << 20;
933                                         break;
934                         default:        goto invalid;
935                 }
936                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
937                 return true;
938         }
940 invalid:
941         internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], rot);
942         return false;
945 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
947         uint64_t mc;
948         int64_t imm;
949         uint8_t *arg1 = ctx->code_position;
950         uint8_t *arg2 = arg1 + arg_size(*arg1);
951         uint8_t *arg3 = arg2 + arg_size(*arg2);
952         ctx->code_position = arg3 + arg_size(*arg3);
953         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])) || unlikely(arg3[0] != ARG_IMM))
954                 goto invalid;
956         imm = get_imm(&arg3[1]) & 0x3f;
958         mc = IA64_I_DEP_IMM;
960         switch (alu) {
961                 case BTX_BTS:   mc |= 1ULL << 36;
962                                 break;
963                 case BTX_BTR:   break;
964                 default:        goto invalid;
965         }
967         mc |= bits_gr(arg1[0]) << 6;
968         mc |= bits_gr(arg2[0]) << 20;
969         mc |= 0ULL << 27;
970         mc |= (imm ^ 0x3f) << 14;
972         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
973         return true;
975 invalid:
976         internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
977         return false;
980 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
982         uint64_t mc;
983         unsigned pred;
984         uint8_t *arg1 = ctx->code_position;
985         uint8_t *arg2 = arg1 + arg_size(*arg1);
986         uint8_t *arg3 = arg2 + arg_size(*arg2);
987         uint8_t *arg4 = arg3 + arg_size(*arg3);
988         ctx->code_position = arg4 + arg_size(*arg4);
989         if (unlikely(arg1[0] != arg2[0]) || unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_p(arg3[0])))
990                 goto invalid;
992         pred = arg3[0];
993         switch (aux) {
994                 case COND_E:    pred ^= 1; break;
995                 case COND_NE:   break;
996                 default:        goto invalid;
997         }
999         if (arg4[0] == ARG_IMM) {
1000                 int64_t imm = get_imm(&arg4[1]);
1001                 if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
1002                         goto invalid;
1003                 mc = IA64_A_ADD_IMM14;
1004                 mc |= bits_gr(arg1[0]) << 6;
1005                 mc |= (imm & 0x7f) << 13;
1006                 mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
1007                 mc |= ((uint64_t)imm >> 13 & 1) << 36;
1008                 mc |= bits_p(pred);
1009                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1010                 return true;
1011         }
1013         if (reg_is_gr(arg4[0])) {
1014                 mc = IA64_A_ADD_IMM14;
1015                 mc |= bits_gr(arg1[0]) << 6;
1016                 mc |= bits_gr(arg4[0]) << 20;
1017                 mc |= bits_p(pred);
1018                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], arg4[0]));
1019                 return true;
1020         }
1022 invalid:
1023         internal(file_line, "cgen_movr: invalid arguments %02x, %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], arg4[0], aux);
1024         return false;
1027 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
1029         uint64_t mc;
1030         unsigned pred;
1031         bool swap_preds = false, swap_regs = false;
1032         uint8_t *arg1 = ctx->code_position;
1033         uint8_t *arg2 = arg1 + arg_size(*arg1);
1034         uint8_t *arg3 = arg2 + arg_size(*arg2);
1035         ctx->code_position = arg3 + arg_size(*arg3);
1037         pred = arg1[0];
1038         mc = IA64_F_FCMP;
1039         switch (aux) {
1040                 case FP_COND_P: mc |= IA64_F_FCMP_UNORD; break;
1041                 case FP_COND_NP:mc |= IA64_F_FCMP_UNORD; swap_preds = true; break;
1042                 case FP_COND_E: mc |= IA64_F_FCMP_EQ; break;
1043                 case FP_COND_NE:mc |= IA64_F_FCMP_EQ; swap_preds = true; break;
1044                 case FP_COND_A: mc |= IA64_F_FCMP_LT; swap_regs = true; break;
1045                 case FP_COND_BE:mc |= IA64_F_FCMP_LE; break;
1046                 case FP_COND_B: mc |= IA64_F_FCMP_LT; break;
1047                 case FP_COND_AE:mc |= IA64_F_FCMP_LE; swap_regs = true; break;
1048         }
1050         if (swap_regs) {
1051                 uint8_t *argx = arg2;
1052                 arg2 = arg3;
1053                 arg3 = argx;
1054         }
1056         if (swap_preds)
1057                 pred ^= 1;
1059         mc |= bits_fp(arg2[0]) << 13;
1060         mc |= bits_fp(arg3[0]) << 20;
1061         mc |= bits_p(pred) << 6;
1062         mc |= bits_p(pred ^ 1) << 27;
1063         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1064         return true;
1067 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1069         uint64_t mc, f1, f2, f3, f4;
1070         uint8_t *arg1 = ctx->code_position;
1071         uint8_t *arg2 = arg1 + arg_size(*arg1);
1072         uint8_t *arg3 = arg2 + arg_size(*arg2);
1073         ctx->code_position = arg3 + arg_size(*arg3);
1074         switch (aux) {
1075                 case FP_ALU_ADD:
1076                         mc = IA64_F_FMA;
1077                         f1 = bits_fp(arg1[0]);
1078                         f2 = bits_fp(arg3[0]);
1079                         f3 = bits_fp(arg2[0]);
1080                         f4 = bits_fp(FR_ONE);
1081                         break;
1082                 case FP_ALU_SUB:
1083                         mc = IA64_F_FMS;
1084                         f1 = bits_fp(arg1[0]);
1085                         f2 = bits_fp(arg3[0]);
1086                         f3 = bits_fp(arg2[0]);
1087                         f4 = bits_fp(FR_ONE);
1088                         break;
1089                 case FP_ALU_MUL:
1090                         mc = IA64_F_FMA;
1091                         f1 = bits_fp(arg1[0]);
1092                         f2 = bits_fp(FR_ZERO);
1093                         f3 = bits_fp(arg2[0]);
1094                         f4 = bits_fp(arg3[0]);
1095                         break;
1096                 default:
1097                         goto invalid;
1098         }
1099         switch (op_size) {
1100                 case OP_SIZE_4:
1101                         mc |= IA64_F_FMA_S;
1102                         break;
1103                 case OP_SIZE_8:
1104                         mc |= IA64_F_FMA_D;
1105                         break;
1106                 case OP_SIZE_10:
1107                         mc |= IA64_F_FMA_E;
1108                         break;
1109                 default:
1110                         goto invalid;
1111         }
1112         mc |= f1 << 6;
1113         mc |= f2 << 13;
1114         mc |= f3 << 20;
1115         mc |= f4 << 27;
1116         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1117         return true;
1119 invalid:
1120         internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, arg1[0], arg2[0], arg3[0]);
1121         return false;
1124 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1126         uint64_t mc;
1127         uint8_t *arg1 = ctx->code_position;
1128         uint8_t *arg2 = arg1 + arg_size(*arg1);
1129         ctx->code_position = arg2 + arg_size(*arg2);
1130         switch (aux) {
1131                 case FP_ALU1_NEG:
1132                         mc = IA64_F_FMERGE_NS;
1133                         mc |= bits_fp(arg1[0]) << 6;
1134                         mc |= bits_fp(arg2[0]) << 13;
1135                         mc |= bits_fp(arg2[0]) << 20;
1136                         break;
1137                 default:
1138                         goto invalid;
1139         }
1140         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1141         return true;
1143 invalid:
1144         internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, arg1[0], arg2[0]);
1145         return false;
1148 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx)
1150         uint64_t mc;
1151         uint8_t *arg1 = ctx->code_position;
1152         uint8_t *arg2 = arg1 + arg_size(*arg1);
1153         ctx->code_position = arg2 + arg_size(*arg2);
1155         mc = IA64_F_FCVT_FX_TRUNC;
1156         mc |= bits_fp(arg1[0]) << 6;
1157         mc |= bits_fp(arg2[0]) << 13;
1158         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1159         return true;
1162 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
1164         uint64_t mc;
1165         uint8_t *arg1 = ctx->code_position;
1166         uint8_t *arg2 = arg1 + arg_size(*arg1);
1167         ctx->code_position = arg2 + arg_size(*arg2);
1169         mc = IA64_F_FCVT_XF;
1170         mc |= bits_fp(arg1[0]) << 6;
1171         mc |= bits_fp(arg2[0]) << 13;
1172         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1174         mc = IA64_F_FMA;
1175         switch (fp_op_size) {
1176                 case OP_SIZE_4:
1177                         mc |= IA64_F_FMA_S;
1178                         break;
1179                 case OP_SIZE_8:
1180                         mc |= IA64_F_FMA_D;
1181                         break;
1182                 case OP_SIZE_10:
1183                         goto skip_norm;
1184                 default:
1185                         goto invalid;
1186         }
1187         mc |= bits_fp(arg1[0]) << 6;
1188         mc |= bits_fp(FR_ZERO) << 13;
1189         mc |= bits_fp(arg1[0]) << 20;
1190         mc |= bits_fp(FR_ONE) << 27;
1191         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING));
1192 skip_norm:
1193         return true;
1195 invalid:
1196         internal(file_line, "cgen_fp_from_int: invalid arguments %u, %02x, %02x", fp_op_size, arg1[0], arg2[0]);
1197         return false;
1200 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
1202         uint64_t mc;
1203         unsigned bundle;
1204         if (length == JMP_SHORTEST) {
1205                 g(ia64_insn(ctx, UNIT_B, IA64_B_BR21, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1206                 bundle = get_free_slot(ctx) - 1;
1207                 ctx->mcode_size += bundle;
1208                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1209                 ctx->mcode_size -= bundle;
1210         } else {
1211                 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1212                 mc = IA64_X_BRL;
1213                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1214                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1215         }
1216         return true;
1219 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
1221         uint64_t mc;
1222         unsigned bundle;
1223         unsigned reg = cget_one(ctx);
1224         if (unlikely(!reg_is_p(reg)))
1225                 goto invalid;
1226         switch (aux) {
1227                 case COND_NE:
1228                         break;
1229                 case COND_E:
1230                         reg ^= 1;
1231                         break;
1232                 default:
1233                         goto invalid;
1234         }
1235         if (likely(length == JMP_SHORTEST)) {
1236                 mc = IA64_B_BR21 | IA64_BR_DPNT;
1237                 mc |= bits_p(reg);
1238                 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1239                 bundle = get_free_slot(ctx) - 1;
1240                 ctx->mcode_size += bundle;
1241                 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
1242                 ctx->mcode_size -= bundle;
1243         } else {
1244                 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1245                 mc = IA64_X_BRL | IA64_BR_DPNT;
1246                 mc |= bits_p(reg);
1247                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1248                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
1249         }
1250         return true;
1251 invalid:
1252         internal(file_line, "cgen_jmp_reg: invalid arguments %x, %x, %x", reg, aux, length);
1255 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
1257         uint64_t mc;
1258         unsigned reg = cget_one(ctx);
1260         mc = IA64_I_MOVE_TO_BR;
1261         mc |= bits_gr(reg) << 13;
1262         mc |= bits_b(R_SCRATCH_B) << 6;
1263         g(ia64_insn(ctx, UNIT_I, mc, R_SCRATCH_B, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1265         mc = IA64_B_BR_JMP_INDIRECT;
1266         mc |= bits_b(R_SCRATCH_B) << 13;
1267         g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1268         return true;
1271 static uint64_t extract_bundle(uint8_t *ptr, unsigned bundle)
1273         uint64_t mc[2];
1274         memcpy(mc, ptr, 16);
1275         switch (bundle) {
1276                 case 0: return mc[0] >> 5 & 0x1ffffffffffULL;
1277                         break;
1278                 case 1: return mc[0] >> 46 | (mc[1] & 0x7fffffULL) << 18;
1279                         break;
1280                 case 2: return mc[1] >> 23;
1281                         break;
1282                 default:internal(file_line, "extract_bundle: invalid bundle %u", bundle);
1283         }
1286 static void insert_bundle(uint8_t *ptr, unsigned bundle, uint64_t instr)
1288         uint64_t mc[2];
1289         memcpy(mc, ptr, 16);
1290         switch (bundle) {
1291                 case 0: mc[0] = (mc[0] & ~(0x1ffffffffffULL << 5)) | instr << 5;
1292                         break;
1293                 case 1: mc[0] = (mc[0] & ~(-1ULL << 46)) | instr << 46;
1294                         mc[1] = (mc[1] & ~0x7fffffULL) | instr >> 18;
1295                         break;
1296                 case 2: mc[1] = (mc[1] & ~(-1ULL << 23)) | instr << 23;
1297                         break;
1298                 default:internal(file_line, "insert_bundle: invalid bundle %u", bundle);
1299         }
1300         memcpy(ptr, mc, 16);
1303 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1305         uint64_t mc;
1306         unsigned imm41;
1307         unsigned bundle = reloc->position & 3;
1308         size_t position = reloc->position & ~3;
1309         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 4) - (int64_t)(position >> 4);
1310         /*debug("relocation: position %lx, bundle %x, offset %lx, label %lx", reloc->position, bundle, offs, ctx->label_to_pos[reloc->label_id]);*/
1311         switch (reloc->length) {
1312                 case JMP_SHORTEST:
1313                         if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
1314                                 return false;
1315                         mc = extract_bundle(ctx->mcode + position, bundle);
1316                         mc &= ~0x011ffffe000ULL;
1317                         mc |= (offs & 0xfffffULL) << 13;
1318                         mc |= ((uint64_t)offs >> 20 & 1) << 36;
1319                         insert_bundle(ctx->mcode + position, bundle, mc);
1320                         return true;
1321                 case JMP_SHORT:
1322                         imm41 = extract_bundle(ctx->mcode + position, 1);
1323                         mc = extract_bundle(ctx->mcode + position, 2);
1324                         mc &= ~0x011ffffe000ULL;
1325                         mc |= (offs & 0xfffffULL) << 13;
1326                         imm41 &= ~0x1fffffffffcULL;
1327                         imm41 |= (offs >> 20 << 2) & 0x1fffffffffcULL;
1328                         mc |= ((uint64_t)offs >> 59 & 1) << 36;
1329                         insert_bundle(ctx->mcode + position, 1, imm41);
1330                         insert_bundle(ctx->mcode + position, 2, mc);
1331                         return true;
1332                 default:
1333                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1334         }
1335         return false;
1338 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1340         bool full;
1341         switch (insn_opcode(insn)) {
1342                 case INSN_ENTRY:
1343                         full = ia64_fill_bundle(ctx);
1344                         if (full)
1345                                 ctx->mcode_size += 16;
1346                         g(cgen_entry(ctx));
1347                         if (full)
1348                                 ctx->mcode_size -= 16;
1349                         return true;
1350                 case INSN_LABEL:
1351                         full = ia64_fill_bundle(ctx);
1352                         if (full)
1353                                 ctx->mcode_size += 16;
1354                         g(cgen_label(ctx));
1355                         if (full)
1356                                 ctx->mcode_size -= 16;
1357                         return true;
1358                 case INSN_RET:
1359                         g(cgen_ia64_ret(ctx));
1360                         g(ia64_purge_bundle(ctx));
1361                         return true;
1362                 case INSN_IA64_ALLOC:
1363                         g(cgen_ia64_alloc(ctx));
1364                         return true;
1365                 case INSN_IA64_DEALLOC:
1366                         g(cgen_ia64_dealloc(ctx));
1367                         return true;
1368                 case INSN_CALL_INDIRECT:
1369                         g(cgen_call_indirect(ctx));
1370                         return true;
1371                 case INSN_MOV:
1372                         g(cgen_mov(ctx, insn_op_size(insn)));
1373                         return true;
1374                 case INSN_MOVSX:
1375                         g(cgen_movsx(ctx, insn_op_size(insn)));
1376                         return true;
1377                 case INSN_CMP_DEST_REG:
1378                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1379                                 goto invalid_insn;
1380                         g(cgen_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
1381                         return true;
1382                 case INSN_TEST_DEST_REG:
1383                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1384                                 goto invalid_insn;
1385                         g(cgen_test_dest_reg(ctx, insn_aux(insn) & 63, insn_aux(insn) >> 6));
1386                         return true;
1387                 case INSN_ALU:
1388                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1389                                 goto invalid_insn;
1390                         g(cgen_alu(ctx, insn_aux(insn)));
1391                         return true;
1392                 case INSN_ALU1:
1393                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1394                                 goto invalid_insn;
1395                         g(cgen_alu1(ctx, insn_aux(insn)));
1396                         return true;
1397                 case INSN_ROT:
1398                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1399                                 goto invalid_insn;
1400                         g(cgen_rot(ctx, insn_aux(insn)));
1401                         return true;
1402                 case INSN_BTX:
1403                         g(cgen_btx(ctx, insn_aux(insn)));
1404                         return true;
1405                 case INSN_MOVR:
1406                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1407                                 goto invalid_insn;
1408                         g(cgen_movr(ctx, insn_aux(insn)));
1409                         return true;
1410                 case INSN_FP_CMP_DEST_REG:
1411                         g(cgen_fp_cmp_dest_reg(ctx, insn_aux(insn)));
1412                         return true;
1413                 case INSN_FP_ALU:
1414                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1415                         return true;
1416                 case INSN_FP_ALU1:
1417                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1418                         return true;
1419                 case INSN_FP_TO_INT64:
1420                         g(cgen_fp_to_int(ctx));
1421                         return true;
1422                 case INSN_FP_FROM_INT64:
1423                         g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1424                         return true;
1425                 case INSN_JMP:
1426                         g(cgen_jmp(ctx, insn_jump_size(insn)));
1427                         return true;
1428                 case INSN_JMP_REG:
1429                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1430                                 goto invalid_insn;
1431                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1432                         return true;
1433                 case INSN_JMP_INDIRECT:
1434                         g(cgen_jmp_indirect(ctx));
1435                         return true;
1436                 default:
1437                 invalid_insn:
1438                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
1439                         return false;
1440         }