codegen: improve constant loading; don't load constants from the code
[ajla.git] / c2-ia64.inc
bloba04cc080685f424d4063761e4ebca3bb8c973142
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         if (bit == ACCESS_NOTHING)
195                 return false;
196         ajla_assert_lo(reg_is_gr(bit) || reg_is_fp(bit) || reg_is_p(bit) || reg_is_b(bit) || bit == ACCESS_MEMORY, (file_line, "test_mask: invalid bit %u", bit));
197         return (mask[bit >> 6] & 1ULL << (bit & 63)) != 0;
200 static void set_mask(uint64_t mask[4], uint8_t bit)
202         if (bit == ACCESS_NOTHING)
203                 return;
204         ajla_assert_lo(reg_is_gr(bit) || reg_is_fp(bit) || reg_is_p(bit) || reg_is_b(bit) || bit == ACCESS_MEMORY, (file_line, "set_mask: invalid bit %u", bit));
205         mask[bit >> 6] |= 1ULL << (bit & 63);
208 static uint32_t get_possible_templates(struct codegen_context *ctx)
210         unsigned i, j;
211         uint32_t result = 0;
212         for (i = 0; i < 32; i++) {
213                 uint32_t tmpl = templates[i];
214                 for (j = 0; j < 3; j++) {
215                         uint8_t insn_unit = ctx->a.insn_units[j];
216                         uint8_t tmpl_unit = tmpl >> (j * 8) & 0xff;
217                         if (!(tmpl_unit & insn_unit)) {
218                                 goto failed_match;
219                         }
220                         if (ctx->a.insn_stops[j] != (tmpl >> (24 + j) & 1)) {
221                                 goto failed_match;
222                         }
223                 }
224                 result |= 1U << i;
225 failed_match:;
226         }
227         return result;
230 static uint64_t get_nop(unsigned unit)
232         switch (unit) {
233                 case UNIT_I:    return IA64_I_NOP;
234                 case UNIT_M:    return IA64_M_NOP;
235                 case UNIT_B:    return IA64_B_NOP;
236                 case UNIT_F:    return IA64_F_NOP;
237                 case UNIT_L:    return IA64_L_NOP;
238                 case UNIT_X:    return IA64_X_NOP;
239                 default:        internal(file_line, "get_nop: invalid unit %x", unit);
240                                 return 0;
241         }
244 static unsigned get_free_slot(struct codegen_context *ctx)
246         unsigned slot = 3;
247         while (slot > 0 && ctx->a.insns[slot - 1] == -1ULL)
248                 slot--;
249         return slot;
252 static bool attr_w ia64_purge_bundle(struct codegen_context *ctx)
254         uint32_t tmpls;
255         unsigned tmpl, i;
256         uint64_t low, high;
257         if (!get_free_slot(ctx))
258                 return true;
259         tmpls = get_possible_templates(ctx);
260         if (unlikely(!tmpls))
261                 internal(file_line, "ia64_purge_bundle: no possible templates");
262         tmpl = low_bit(tmpls);
263         for (i = 0; i < 3; i++) {
264                 if (ctx->a.insns[i] == -1ULL) {
265                         ctx->a.insns[i] = get_nop(templates[tmpl] >> (i * 8) & 0xff);
266                         ctx->a.insn_units[i] = templates[tmpl] >> (i * 8) & 0xff;
267                 }
268         }
269         low = tmpl | ctx->a.insns[0] << 5 | ctx->a.insns[1] << 46;
270         high = ctx->a.insns[1] >> 18 | ctx->a.insns[2] << 23;
271         cgen_eight(low);
272         cgen_eight(high);
273         new_bundle(ctx);
274         return true;
277 static bool ia64_fill_bundle(struct codegen_context *ctx)
279         uint32_t tmpls;
280         unsigned tmpl, i;
281         if (!get_free_slot(ctx))
282                 return false;
283         tmpls = get_possible_templates(ctx);
284         if (unlikely(!tmpls))
285                 internal(file_line, "ia64_fill_bundle: no possible templates");
286         tmpl = low_bit(tmpls);
287         for (i = 0; i < 3; i++) {
288                 if (ctx->a.insns[i] == -1ULL) {
289                         ctx->a.insns[i] = get_nop(templates[tmpl] >> (i * 8) & 0xff);
290                         ctx->a.insn_units[i] = templates[tmpl] >> (i * 8) & 0xff;
291                 }
292         }
293         return true;
296 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)
298         unsigned slot = get_free_slot(ctx);
299         bool need_stop = false;
300         need_stop |= test_mask(ctx->a.wr_mask, wr1);
301         need_stop |= test_mask(ctx->a.wr_mask, wr2);
302         need_stop |= test_mask(ctx->a.wr_mask, rd1);
303         need_stop |= test_mask(ctx->a.wr_mask, rd2);
304         need_stop |= test_mask(ctx->a.wr_mask, rd3);
305         /*debug("ia64_insn: %x, %lx, %d, %u", unit, mc, need_stop, slot);*/
306         if (slot > 0) {
307                 if (need_stop) {
308 try_stop_in_next_slot:
309                         ctx->a.insn_stops[slot - 1] = need_stop;
310                         if (!get_possible_templates(ctx)) {
311                                 ctx->a.insn_stops[slot - 1] = false;
312                                 slot++;
313                                 if (unlikely(slot > 3))
314                                         internal(file_line, "ia64_insn: can't set stop at the end of the bundle");
315                                 goto try_stop_in_next_slot;
316                         }
317                 }
318                 if (slot == 3) {
319                         g(ia64_purge_bundle(ctx));
320                         slot = 0;
321                 }
322                 if (need_stop) {
323                         clear_wr_mask(ctx);
324                 }
325         }
326 try_next_slot:
327         ctx->a.insn_units[slot] = unit;
328         if (!get_possible_templates(ctx)) {
329                 ctx->a.insn_units[slot] = 0xff;
330                 slot++;
331                 if (unlikely(slot == 3)) {
332                         g(ia64_purge_bundle(ctx));
333                         slot = 0;
334                 }
335                 goto try_next_slot;
336         }
337         ctx->a.insns[slot] = mc;
338         set_mask(ctx->a.wr_mask, wr1);
339         set_mask(ctx->a.wr_mask, wr2);
340         return true;
343 static bool attr_w cgen_ia64_ret(struct codegen_context *ctx)
345         uint64_t mc;
346         mc = IA64_B_BR_RET;
347         mc |= bits_b(B_0) << 13;
348         g(ia64_insn(ctx, UNIT_B, mc, ACCESS_MEMORY, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
349         mc = IA64_B_NOP;
350         g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_MEMORY, ACCESS_NOTHING, ACCESS_NOTHING));
351         return true;
354 static bool attr_w cgen_ia64_alloc(struct codegen_context *ctx)
356         uint64_t mc;
357         uint8_t *arg1 = ctx->code_position;
358         uint8_t *arg2 = arg1 + arg_size(*arg1);
359         uint8_t *arg3 = arg2 + arg_size(*arg2);
360         ctx->code_position = arg3 + arg_size(*arg3);
361         ia64_fill_bundle(ctx);
362         mc = IA64_M_ALLOC;
363         mc |= bits_gr(arg1[0]) << 6;
364         mc |= get_imm(&arg2[1]) << 13;
365         mc |= get_imm(&arg3[1]) << 20;
366         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
367         return true;
370 static bool attr_w cgen_ia64_dealloc(struct codegen_context *ctx)
372         uint64_t mc;
373         uint8_t *arg1 = ctx->code_position;
374         ctx->code_position = arg1 + arg_size(*arg1);
375         mc = IA64_I_MOV_TO_AR | IA64_I_MOV_TO_AR_PFS;
376         mc |= bits_gr(arg1[0]) << 13;
377         g(ia64_insn(ctx, UNIT_I, mc, ACCESS_NOTHING, ACCESS_NOTHING, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING));
378         return true;
381 static bool attr_w cgen_call_indirect(struct codegen_context *ctx)
383         uint64_t mc;
384         unsigned reg = cget_one(ctx);
385         mc = IA64_B_BR_CALL_INDIRECT;
386         mc |= bits_b(B_0) << 6;
387         mc |= bits_b(reg) << 13;
388         g(ia64_insn(ctx, UNIT_B, mc, B_0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
389         return true;
392 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
394         uint64_t mc;
395         int64_t imm;
396         uint8_t z = R_ZERO;
397         uint8_t *arg1 = ctx->code_position;
398         uint8_t *arg2 = arg1 + arg_size(*arg1);
399         ctx->code_position = arg2 + arg_size(*arg2);
401         if (reg_is_gr(arg1[0])) {
402                 if (reg_is_gr(arg2[0])) {
403                         switch (size) {
404                                 case OP_SIZE_1:
405                                         mc = IA64_I_ZXT1;
406                                         break;
407                                 case OP_SIZE_2:
408                                         mc = IA64_I_ZXT2;
409                                         break;
410                                 case OP_SIZE_4:
411                                         mc = IA64_I_ZXT4;
412                                         break;
413                                 case OP_SIZE_NATIVE:
414                                         mc = IA64_A_ADD_IMM14;
415                                         mc |= bits_gr(arg1[0]) << 6;
416                                         mc |= bits_gr(arg2[0]) << 20;
417                                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
418                                         return true;
419                                 default:
420                                         goto invalid;
421                         }
422                         mc |= bits_gr(arg1[0]) << 6;
423                         mc |= bits_gr(arg2[0]) << 20;
424                         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
425                         return true;
426                 }
427                 if (reg_is_fp(arg2[0])) {
428                         mc = IA64_M_GETF_SIG;
429                         mc |= bits_gr(arg1[0]) << 6;
430                         mc |= bits_fp(arg2[0]) << 13;
431                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
432                         return true;
433                 }
434                 if (reg_is_b(arg2[0])) {
435                         mc = IA64_I_MOVE_FROM_BR;
436                         mc |= bits_gr(arg1[0]) << 6;
437                         mc |= bits_b(arg2[0]) << 13;
438                         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
439                         return true;
440                 }
441                 if (reg_is_p(arg2[0])) {
442                         mc = IA64_A_ADD_IMM14;
443                         mc |= bits_gr(arg1[0]) << 6;
444                         mc |= (uint64_t)1 << 13;
445                         mc |= bits_p(arg2[0]);
446                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
448                         mc = IA64_A_ADD_IMM14;
449                         mc |= bits_gr(arg1[0]) << 6;
450                         mc |= bits_p(arg2[0] ^ 1);
451                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
453                         return true;
454                 }
455                 if (arg2[0] == ARG_ADDRESS_1) {
456                         imm = get_imm(&arg2[2]);
457                         if (unlikely(imm != 0))
458                                 goto invalid;
459                         switch (size) {
460                                 case OP_SIZE_1: mc = IA64_M_LD1; break;
461                                 case OP_SIZE_2: mc = IA64_M_LD2; break;
462                                 case OP_SIZE_4: mc = IA64_M_LD4; break;
463                                 case OP_SIZE_8: mc = IA64_M_LD8; break;
464                                 default:        goto invalid;
465                         }
466                         mc |= bits_gr(arg1[0]) << 6;
467                         mc |= bits_gr(arg2[1]) << 20;
468                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_MEMORY, ACCESS_NOTHING));
469                         return true;
470                 }
471                 if (arg2[0] == ARG_IMM) {
472                         imm = get_imm(&arg2[1]);
473                         if (imm >= -0x200000 && imm < 0x200000) {
474                                 mc = IA64_A_ADD_IMM22;
475                                 mc |= bits_gr(arg1[0]) << 6;
476                                 mc |= (imm & 0x7f) << 13;
477                                 mc |= ((uint64_t)imm >> 7 & 0x1ff) << 27;
478                                 mc |= ((uint64_t)imm >> 16 & 0x1f) << 22;
479                                 mc |= ((uint64_t)imm >> 21 & 0x1) << 36;
480                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
481                                 return true;
482                         } else {
483                                 mc = (imm & 0x7fffffffffc00000ULL) >> 22;
484                                 g(ia64_insn(ctx, UNIT_L, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
485                                 mc = IA64_X_MOVL;
486                                 mc |= bits_gr(arg1[0]) << 6;
487                                 mc |= (imm & 0x7f) << 13;
488                                 mc |= ((uint64_t)imm >> 7 & 0x1ff) << 27;
489                                 mc |= ((uint64_t)imm >> 16 & 0x1f) << 22;
490                                 mc |= ((uint64_t)imm >> 21 & 0x1) << 21;
491                                 mc |= ((uint64_t)imm >> 63) << 36;
492                                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
493                                 return true;
494                         }
495                 }
496         }
497         if (reg_is_fp(arg1[0])) {
498                 if (reg_is_gr(arg2[0])) {
499                         mc = IA64_M_SETF_SIG;
500                         mc |= bits_fp(arg1[0]) << 6;
501                         mc |= bits_gr(arg2[0]) << 13;
502                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
503                         return true;
504                 }
505                 if (reg_is_fp(arg2[0])) {
506                         mc = IA64_F_FMERGE_S;
507                         mc |= bits_fp(arg1[0]) << 6;
508                         mc |= bits_fp(arg2[0]) << 13;
509                         mc |= bits_fp(arg2[0]) << 20;
510                         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
511                         return true;
512                 }
513                 if (arg2[0] == ARG_ADDRESS_1) {
514                         imm = get_imm(&arg2[2]);
515                         if (unlikely(imm != 0))
516                                 goto invalid;
517                         switch (size) {
518                                 case OP_SIZE_4: mc = IA64_M_LDFS; break;
519                                 case OP_SIZE_8: mc = IA64_M_LDFD; break;
520                                 case OP_SIZE_10:mc = IA64_M_LDFE; break;
521                                 default:        goto invalid;
522                         }
523                         mc |= bits_fp(arg1[0]) << 6;
524                         mc |= bits_gr(arg2[1]) << 20;
525                         g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_MEMORY, ACCESS_NOTHING));
526                         return true;
527                 }
528         }
529         if (reg_is_b(arg1[0])) {
530                 if (reg_is_gr(arg2[0])) {
531                         mc = IA64_I_MOVE_TO_BR;
532                         mc |= bits_gr(arg2[0]) << 13;
533                         mc |= bits_b(arg1[0]) << 6;
534                         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
535                         return true;
536                 }
537         }
538         if (arg1[0] == ARG_ADDRESS_1) {
539                 imm = get_imm(&arg1[2]);
540                 if (unlikely(imm != 0))
541                         goto invalid;
542                 if (arg2[0] == ARG_IMM) {
543                         imm = get_imm(&arg2[1]);
544                         if (unlikely(imm != 0))
545                                 goto invalid;
546                         arg2 = &z;
547                 }
548                 if (reg_is_gr(arg2[0])) {
549                         switch (size) {
550                                 case OP_SIZE_1: mc = IA64_M_ST1; break;
551                                 case OP_SIZE_2: mc = IA64_M_ST2; break;
552                                 case OP_SIZE_4: mc = IA64_M_ST4; break;
553                                 case OP_SIZE_8: mc = IA64_M_ST8; break;
554                                 default:        goto invalid;
555                         }
556                         mc |= bits_gr(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                 if (reg_is_fp(arg2[0])) {
562                         switch (size) {
563                                 case OP_SIZE_4: mc = IA64_M_STFS; break;
564                                 case OP_SIZE_8: mc = IA64_M_STFD; break;
565                                 case OP_SIZE_10:mc = IA64_M_STFE; break;
566                                 default:        goto invalid;
567                         }
568                         mc |= bits_fp(arg2[0]) << 13;
569                         mc |= bits_gr(arg1[1]) << 20;
570                         g(ia64_insn(ctx, UNIT_M, mc, ACCESS_MEMORY, ACCESS_NOTHING, arg1[1], arg2[0], ACCESS_NOTHING));
571                         return true;
572                 }
573         }
575 invalid:
576         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
577         return false;
580 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
582         uint64_t mc;
583         uint8_t *arg1 = ctx->code_position;
584         uint8_t *arg2 = arg1 + arg_size(*arg1);
585         ctx->code_position = arg2 + arg_size(*arg2);
587         if (likely(reg_is_gr(arg1[0])) && likely(reg_is_gr(arg2[0]))) {
588                 switch (size) {
589                         case OP_SIZE_1:
590                                 mc = IA64_I_SXT1;
591                                 break;
592                         case OP_SIZE_2:
593                                 mc = IA64_I_SXT2;
594                                 break;
595                         case OP_SIZE_4:
596                                 mc = IA64_I_SXT4;
597                                 break;
598                         case OP_SIZE_NATIVE:
599                                 mc = IA64_A_ADD_IMM14;
600                                 mc |= bits_gr(arg1[0]) << 6;
601                                 mc |= bits_gr(arg2[0]) << 20;
602                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
603                                 return true;
604                         default:
605                                 goto invalid;
606                 }
607                 mc |= bits_gr(arg1[0]) << 6;
608                 mc |= bits_gr(arg2[0]) << 20;
609                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
610                 return true;
611         }
613 invalid:
614         internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u", arg1[0], arg2[0], size);
615         return false;
618 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned cond)
620         uint64_t mc;
621         unsigned pred;
622         bool swap_preds = false, swap_regs = false;
623         uint8_t z = R_ZERO;
624         uint8_t *arg1 = ctx->code_position;
625         uint8_t *arg2 = arg1 + arg_size(*arg1);
626         uint8_t *arg3 = arg2 + arg_size(*arg2);
627         ctx->code_position = arg3 + arg_size(*arg3);
629         if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
630                 goto invalid;
632         pred = arg1[0];
634         if (arg3[0] == ARG_IMM) {
635                 int64_t imm = get_imm(&arg3[1]);
636                 if (likely(!imm)) {
637                         arg3 = &z;
638                         goto cmp_3reg;
639                 }
640                 if (unlikely(imm <= -0x80) || unlikely(imm >= 0x80))
641                         goto invalid;
642                 switch (cond) {
643                         case COND_AE:   mc = IA64_A_CMP_LTU_IMM8; imm--; break;
644                         case COND_B:    mc = IA64_A_CMP_LTU_IMM8; imm--; swap_preds = true; break;
645                         case COND_E:    mc = IA64_A_CMP_EQ_IMM8; break;
646                         case COND_NE:   mc = IA64_A_CMP_EQ_IMM8; swap_preds = true; break;
647                         case COND_BE:   mc = IA64_A_CMP_LTU_IMM8; swap_preds = true; break;
648                         case COND_A:    mc = IA64_A_CMP_LTU_IMM8; break;
649                         case COND_L:    mc = IA64_A_CMP_LT_IMM8; imm--; swap_preds = true; break;
650                         case COND_GE:   mc = IA64_A_CMP_LT_IMM8; imm--; break;
651                         case COND_LE:   mc = IA64_A_CMP_LT_IMM8; swap_preds = true; break;
652                         case COND_G:    mc = IA64_A_CMP_LT_IMM8; break;
653                         default:        goto invalid;
654                 }
656                 if (swap_preds)
657                         pred ^= 1;
659                 if (op_size == OP_SIZE_4)
660                         mc |= IA64_A_CMP4;
662                 mc |= (imm & 0x7f) << 13;
663                 mc |= ((uint64_t)imm >> 7 & 1) << 36;
664                 mc |= bits_gr(arg2[0]) << 20;
665                 mc |= bits_p(pred) << 6;
666                 mc |= bits_p(pred ^ 1) << 27;
667                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
668                 return true;
669         }
671         if (!reg_is_gr(arg3[0]))
672                 goto invalid;
674 cmp_3reg:
675         switch (cond) {
676                 case COND_B:    mc = IA64_A_CMP_LTU; break;
677                 case COND_AE:   mc = IA64_A_CMP_LTU; swap_preds = true; break;
678                 case COND_E:    mc = IA64_A_CMP_EQ; break;
679                 case COND_NE:   mc = IA64_A_CMP_EQ; swap_preds = true; break;
680                 case COND_BE:   mc = IA64_A_CMP_LTU; swap_regs = true; swap_preds = true; break;
681                 case COND_A:    mc = IA64_A_CMP_LTU; swap_regs = true; break;
682                 case COND_L:    mc = IA64_A_CMP_LT; break;
683                 case COND_GE:   mc = IA64_A_CMP_LT; swap_preds = true; break;
684                 case COND_LE:   mc = IA64_A_CMP_LT; swap_regs = true; swap_preds = true; break;
685                 case COND_G:    mc = IA64_A_CMP_LT; swap_regs = true; break;
686                 default:        goto invalid;
687         }
689         if (swap_regs) {
690                 uint8_t *argx = arg2;
691                 arg2 = arg3;
692                 arg3 = argx;
693         }
695         if (swap_preds)
696                 pred ^= 1;
698         if (op_size == OP_SIZE_4)
699                 mc |= IA64_A_CMP4;
701         mc |= bits_gr(arg2[0]) << 13;
702         mc |= bits_gr(arg3[0]) << 20;
703         mc |= bits_p(pred) << 6;
704         mc |= bits_p(pred ^ 1) << 27;
705         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], arg3[0], ACCESS_NOTHING));
706         return true;
708 invalid:
709         internal(file_line, "cgen_cmp_dest_reg: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
710         return false;
713 static bool attr_w cgen_test_dest_reg(struct codegen_context *ctx, unsigned bit, bool jnz)
715         uint64_t mc;
716         unsigned pred;
717         uint8_t *arg1 = ctx->code_position;
718         uint8_t *arg2 = arg1 + arg_size(*arg1);
719         ctx->code_position = arg2 + arg_size(*arg2);
721         if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
722                 goto invalid;
724         pred = arg1[0];
726         if (jnz)
727                 pred ^= 1;
729         mc = IA64_I_TBIT;
730         mc |= (uint64_t)bit << 14;
731         mc |= bits_gr(arg2[0]) << 20;
732         mc |= bits_p(pred) << 6;
733         mc |= bits_p(pred ^ 1) << 27;
734         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], arg1[0] ^ 1, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
735         return true;
737 invalid:
738         internal(file_line, "cgen_test_dest_reg: invalid arguments %02x, %02x", arg1[0], arg2[0]);
739         return false;
742 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned alu)
744         uint64_t mc;
745         uint8_t *arg1 = ctx->code_position;
746         uint8_t *arg2 = arg1 + arg_size(*arg1);
747         uint8_t *arg3 = arg2 + arg_size(*arg2);
748         ctx->code_position = arg3 + arg_size(*arg3);
750         if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
751                 uint8_t *arg_swp = arg3;
752                 arg3 = arg2;
753                 arg2 = arg_swp;
754         }
756         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
757                 goto invalid;
759 gr_gr_gr:
760         if (reg_is_gr(arg3[0])) {
761                 mc = IA64_A_ALU;
762                 switch (alu) {
763                         case ALU_ADD:   mc |= IA64_A_ALU_ADD; break;
764                         case ALU_SUB:   mc |= IA64_A_ALU_SUB; break;
765                         case ALU_AND:   mc |= IA64_A_ALU_AND; break;
766                         case ALU_ANDN:  mc |= IA64_A_ALU_ANDCM; break;
767                         case ALU_OR:    mc |= IA64_A_ALU_OR; break;
768                         case ALU_XOR:   mc |= IA64_A_ALU_XOR; break;
769                         default:        goto invalid;
770                 }
771                 mc |= bits_gr(arg1[0]) << 6;
772                 mc |= bits_gr(arg2[0]) << 13;
773                 mc |= bits_gr(arg3[0]) << 20;
774                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
775                 return true;
776         }
778         if (arg3[0] == ARG_SHIFTED_REGISTER && (arg3[1] & ARG_SHIFT_MODE) == ARG_SHIFT_LSL) {
779                 unsigned amount = arg3[1] & ARG_SHIFT_AMOUNT;
780                 if (!amount) {
781                         arg3 += 2;
782                         goto gr_gr_gr;
783                 }
784                 if (unlikely(amount > 4))
785                         goto invalid;
786                 mc = IA64_A_SHLADD;
787                 mc |= bits_gr(arg1[0]) << 6;
788                 mc |= bits_gr(arg3[2]) << 13;
789                 mc |= bits_gr(arg2[0]) << 20;
790                 mc |= (amount - 1) << 27;
791                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[2], ACCESS_NOTHING));
792                 return true;
793         }
795         if (arg3[0] == ARG_IMM) {
796                 int64_t imm = get_imm(&arg3[1]);
797                 if (alu == ALU_SUB) {
798                         imm = -(uint64_t)imm;
799                         alu = ALU_ADD;
800                 }
801                 if (alu == ALU_ADD) {
802                         if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
803                                 goto invalid;
804                         mc = IA64_A_ADD_IMM14;
805                         mc |= bits_gr(arg1[0]) << 6;
806                         mc |= bits_gr(arg2[0]) << 20;
807                         mc |= (imm & 0x7f) << 13;
808                         mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
809                         mc |= ((uint64_t)imm >> 13 & 1) << 36;
810                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
811                         return true;
812                 } else if (alu == ALU_AND || alu == ALU_OR || alu == ALU_XOR) {
813                         if (unlikely(imm < -0x80) || unlikely(imm >= 0x80))
814                                 goto invalid;
815                         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);
816                         mc |= bits_gr(arg1[0]) << 6;
817                         mc |= bits_gr(arg2[0]) << 20;
818                         mc |= (imm & 0x7f) << 13;
819                         mc |= ((uint64_t)imm >> 7 & 1) << 36;
820                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
821                         return true;
822                 } else {
823                         goto invalid;
824                 }
825         }
827 invalid:
828         internal(file_line, "cgen_alu: invalid arguments %u, %02x, %02x, %02x", alu, arg1[0], arg2[0], arg3[0]);
829         return false;
832 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned alu)
834         uint64_t mc;
835         uint8_t *arg1 = ctx->code_position;
836         uint8_t *arg2 = arg1 + arg_size(*arg1);
837         ctx->code_position = arg2 + arg_size(*arg2);
839         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
840                 goto invalid;
843         switch (alu) {
844                 case ALU1_NOT:  mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_ANDCM;
845                                 mc |= bits_gr(arg1[0]) << 6;
846                                 mc |= bits_gr(arg2[0]) << 20;
847                                 mc |= 0x7fULL << 13;
848                                 mc |= 0x1ULL << 36;
849                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
850                                 return true;
851                 case ALU1_NEG:  mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_SUB;
852                                 mc |= bits_gr(arg1[0]) << 6;
853                                 mc |= bits_gr(arg2[0]) << 20;
854                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
855                                 return true;
856                 case ALU1_INC:  mc = IA64_A_ADD_IMM14;
857                                 mc |= bits_gr(arg1[0]) << 6;
858                                 mc |= bits_gr(arg2[0]) << 20;
859                                 mc |= 1ULL << 13;
860                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
861                                 return true;
862                 case ALU1_DEC:  mc = IA64_A_ADD_IMM14;
863                                 mc |= bits_gr(arg1[0]) << 6;
864                                 mc |= bits_gr(arg2[0]) << 20;
865                                 mc |= 0x7fULL << 13;
866                                 mc |= 0x3fULL << 27;
867                                 mc |= 0x1ULL << 36;
868                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
869                                 return true;
870                 case ALU1_BSWAP:mc = IA64_I_MUX1_REV;
871                                 mc |= bits_gr(arg1[0]) << 6;
872                                 mc |= bits_gr(arg1[1]) << 13;
873                                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
874                                 return true;
875                 case ALU1_POPCNT:
876                                 mc = IA64_I_POPCNT;
877                                 mc |= bits_gr(arg1[0]) << 6;
878                                 mc |= bits_gr(arg2[0]) << 20;
879                                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
880                                 return true;
881                 default:        goto invalid;
882         }
884 invalid:
885         internal(file_line, "cgen_alu1: invalid arguments %u, %02x, %02x", alu, arg1[0], arg2[0]);
886         return false;
890 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned rot)
892         uint64_t mc;
893         uint8_t *arg1 = ctx->code_position;
894         uint8_t *arg2 = arg1 + arg_size(*arg1);
895         uint8_t *arg3 = arg2 + arg_size(*arg2);
896         ctx->code_position = arg3 + arg_size(*arg3);
898         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
899                 goto invalid;
901         if (arg3[0] == ARG_IMM) {
902                 uint64_t pos = get_imm(&arg3[1]) & 63;
903                 uint64_t len = 64 - pos - 1;
904                 switch (rot) {
905                         case ROT_SHL:   mc = IA64_I_DEP_Z;
906                                         mc |= bits_gr(arg1[0]) << 6;
907                                         mc |= bits_gr(arg2[0]) << 13;
908                                         mc |= (pos ^ 0x3f) << 20;
909                                         mc |= len << 27;
910                                         break;
911                         case ROT_SHR:   mc = IA64_I_EXTR_U;
912                                         mc |= bits_gr(arg1[0]) << 6;
913                                         mc |= pos << 14;
914                                         mc |= bits_gr(arg2[0]) << 20;
915                                         mc |= len << 27;
916                                         break;
917                         case ROT_SAR:   mc = IA64_I_EXTR;
918                                         mc |= bits_gr(arg1[0]) << 6;
919                                         mc |= pos << 14;
920                                         mc |= bits_gr(arg2[0]) << 20;
921                                         mc |= len << 27;
922                                         break;
923                         default:        goto invalid;
924                 }
925                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
926                 return true;
927         }
929         if (reg_is_gr(arg3[0])) {
930                 switch (rot) {
931                         case ROT_SHL:   mc = IA64_I_SHL;
932                                         mc |= bits_gr(arg1[0]) << 6;
933                                         mc |= bits_gr(arg2[0]) << 13;
934                                         mc |= bits_gr(arg3[0]) << 20;
935                                         break;
936                         case ROT_SHR:   mc = IA64_I_SHR_U;
937                                         mc |= bits_gr(arg1[0]) << 6;
938                                         mc |= bits_gr(arg3[0]) << 13;
939                                         mc |= bits_gr(arg2[0]) << 20;
940                                         break;
941                         case ROT_SAR:   mc = IA64_I_SHR;
942                                         mc |= bits_gr(arg1[0]) << 6;
943                                         mc |= bits_gr(arg3[0]) << 13;
944                                         mc |= bits_gr(arg2[0]) << 20;
945                                         break;
946                         default:        goto invalid;
947                 }
948                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
949                 return true;
950         }
952 invalid:
953         internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], rot);
954         return false;
957 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
959         uint64_t mc;
960         int64_t imm;
961         uint8_t *arg1 = ctx->code_position;
962         uint8_t *arg2 = arg1 + arg_size(*arg1);
963         uint8_t *arg3 = arg2 + arg_size(*arg2);
964         ctx->code_position = arg3 + arg_size(*arg3);
965         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])) || unlikely(arg3[0] != ARG_IMM))
966                 goto invalid;
968         imm = get_imm(&arg3[1]) & 0x3f;
970         mc = IA64_I_DEP_IMM;
972         switch (alu) {
973                 case BTX_BTS:   mc |= 1ULL << 36;
974                                 break;
975                 case BTX_BTR:   break;
976                 default:        goto invalid;
977         }
979         mc |= bits_gr(arg1[0]) << 6;
980         mc |= bits_gr(arg2[0]) << 20;
981         mc |= 0ULL << 27;
982         mc |= (imm ^ 0x3f) << 14;
984         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
985         return true;
987 invalid:
988         internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
989         return false;
992 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
994         uint64_t mc;
995         unsigned pred;
996         uint8_t *arg1 = ctx->code_position;
997         uint8_t *arg2 = arg1 + arg_size(*arg1);
998         uint8_t *arg3 = arg2 + arg_size(*arg2);
999         uint8_t *arg4 = arg3 + arg_size(*arg3);
1000         ctx->code_position = arg4 + arg_size(*arg4);
1001         if (unlikely(arg1[0] != arg2[0]) || unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_p(arg3[0])))
1002                 goto invalid;
1004         pred = arg3[0];
1005         switch (aux) {
1006                 case COND_E:    pred ^= 1; break;
1007                 case COND_NE:   break;
1008                 default:        goto invalid;
1009         }
1011         if (arg4[0] == ARG_IMM) {
1012                 int64_t imm = get_imm(&arg4[1]);
1013                 if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
1014                         goto invalid;
1015                 mc = IA64_A_ADD_IMM14;
1016                 mc |= bits_gr(arg1[0]) << 6;
1017                 mc |= (imm & 0x7f) << 13;
1018                 mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
1019                 mc |= ((uint64_t)imm >> 13 & 1) << 36;
1020                 mc |= bits_p(pred);
1021                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1022                 return true;
1023         }
1025         if (reg_is_gr(arg4[0])) {
1026                 mc = IA64_A_ADD_IMM14;
1027                 mc |= bits_gr(arg1[0]) << 6;
1028                 mc |= bits_gr(arg4[0]) << 20;
1029                 mc |= bits_p(pred);
1030                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], arg4[0]));
1031                 return true;
1032         }
1034 invalid:
1035         internal(file_line, "cgen_movr: invalid arguments %02x, %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], arg4[0], aux);
1036         return false;
1039 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
1041         uint64_t mc;
1042         unsigned pred;
1043         bool swap_preds = false, swap_regs = false;
1044         uint8_t *arg1 = ctx->code_position;
1045         uint8_t *arg2 = arg1 + arg_size(*arg1);
1046         uint8_t *arg3 = arg2 + arg_size(*arg2);
1047         ctx->code_position = arg3 + arg_size(*arg3);
1049         pred = arg1[0];
1050         mc = IA64_F_FCMP;
1051         switch (aux) {
1052                 case FP_COND_P: mc |= IA64_F_FCMP_UNORD; break;
1053                 case FP_COND_NP:mc |= IA64_F_FCMP_UNORD; swap_preds = true; break;
1054                 case FP_COND_E: mc |= IA64_F_FCMP_EQ; break;
1055                 case FP_COND_NE:mc |= IA64_F_FCMP_EQ; swap_preds = true; break;
1056                 case FP_COND_A: mc |= IA64_F_FCMP_LT; swap_regs = true; break;
1057                 case FP_COND_BE:mc |= IA64_F_FCMP_LE; break;
1058                 case FP_COND_B: mc |= IA64_F_FCMP_LT; break;
1059                 case FP_COND_AE:mc |= IA64_F_FCMP_LE; swap_regs = true; break;
1060         }
1062         if (swap_regs) {
1063                 uint8_t *argx = arg2;
1064                 arg2 = arg3;
1065                 arg3 = argx;
1066         }
1068         if (swap_preds)
1069                 pred ^= 1;
1071         mc |= bits_fp(arg2[0]) << 13;
1072         mc |= bits_fp(arg3[0]) << 20;
1073         mc |= bits_p(pred) << 6;
1074         mc |= bits_p(pred ^ 1) << 27;
1075         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1076         return true;
1079 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1081         uint64_t mc, f1, f2, f3, f4;
1082         uint8_t *arg1 = ctx->code_position;
1083         uint8_t *arg2 = arg1 + arg_size(*arg1);
1084         uint8_t *arg3 = arg2 + arg_size(*arg2);
1085         ctx->code_position = arg3 + arg_size(*arg3);
1086         switch (aux) {
1087                 case FP_ALU_ADD:
1088                         mc = IA64_F_FMA;
1089                         f1 = bits_fp(arg1[0]);
1090                         f2 = bits_fp(arg3[0]);
1091                         f3 = bits_fp(arg2[0]);
1092                         f4 = bits_fp(FR_ONE);
1093                         break;
1094                 case FP_ALU_SUB:
1095                         mc = IA64_F_FMS;
1096                         f1 = bits_fp(arg1[0]);
1097                         f2 = bits_fp(arg3[0]);
1098                         f3 = bits_fp(arg2[0]);
1099                         f4 = bits_fp(FR_ONE);
1100                         break;
1101                 case FP_ALU_MUL:
1102                         mc = IA64_F_FMA;
1103                         f1 = bits_fp(arg1[0]);
1104                         f2 = bits_fp(FR_ZERO);
1105                         f3 = bits_fp(arg2[0]);
1106                         f4 = bits_fp(arg3[0]);
1107                         break;
1108                 default:
1109                         goto invalid;
1110         }
1111         switch (op_size) {
1112                 case OP_SIZE_4:
1113                         mc |= IA64_F_FMA_S;
1114                         break;
1115                 case OP_SIZE_8:
1116                         mc |= IA64_F_FMA_D;
1117                         break;
1118                 case OP_SIZE_10:
1119                         mc |= IA64_F_FMA_E;
1120                         break;
1121                 default:
1122                         goto invalid;
1123         }
1124         mc |= f1 << 6;
1125         mc |= f2 << 13;
1126         mc |= f3 << 20;
1127         mc |= f4 << 27;
1128         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1129         return true;
1131 invalid:
1132         internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, arg1[0], arg2[0], arg3[0]);
1133         return false;
1136 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1138         uint64_t mc;
1139         uint8_t *arg1 = ctx->code_position;
1140         uint8_t *arg2 = arg1 + arg_size(*arg1);
1141         ctx->code_position = arg2 + arg_size(*arg2);
1142         switch (aux) {
1143                 case FP_ALU1_NEG:
1144                         mc = IA64_F_FMERGE_NS;
1145                         mc |= bits_fp(arg1[0]) << 6;
1146                         mc |= bits_fp(arg2[0]) << 13;
1147                         mc |= bits_fp(arg2[0]) << 20;
1148                         break;
1149                 default:
1150                         goto invalid;
1151         }
1152         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1153         return true;
1155 invalid:
1156         internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, arg1[0], arg2[0]);
1157         return false;
1160 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx)
1162         uint64_t mc;
1163         uint8_t *arg1 = ctx->code_position;
1164         uint8_t *arg2 = arg1 + arg_size(*arg1);
1165         ctx->code_position = arg2 + arg_size(*arg2);
1167         mc = IA64_F_FCVT_FX_TRUNC;
1168         mc |= bits_fp(arg1[0]) << 6;
1169         mc |= bits_fp(arg2[0]) << 13;
1170         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1171         return true;
1174 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
1176         uint64_t mc;
1177         uint8_t *arg1 = ctx->code_position;
1178         uint8_t *arg2 = arg1 + arg_size(*arg1);
1179         ctx->code_position = arg2 + arg_size(*arg2);
1181         mc = IA64_F_FCVT_XF;
1182         mc |= bits_fp(arg1[0]) << 6;
1183         mc |= bits_fp(arg2[0]) << 13;
1184         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1186         mc = IA64_F_FMA;
1187         switch (fp_op_size) {
1188                 case OP_SIZE_4:
1189                         mc |= IA64_F_FMA_S;
1190                         break;
1191                 case OP_SIZE_8:
1192                         mc |= IA64_F_FMA_D;
1193                         break;
1194                 case OP_SIZE_10:
1195                         goto skip_norm;
1196                 default:
1197                         goto invalid;
1198         }
1199         mc |= bits_fp(arg1[0]) << 6;
1200         mc |= bits_fp(FR_ZERO) << 13;
1201         mc |= bits_fp(arg1[0]) << 20;
1202         mc |= bits_fp(FR_ONE) << 27;
1203         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING));
1204 skip_norm:
1205         return true;
1207 invalid:
1208         internal(file_line, "cgen_fp_from_int: invalid arguments %u, %02x, %02x", fp_op_size, arg1[0], arg2[0]);
1209         return false;
1212 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
1214         uint64_t mc;
1215         unsigned bundle;
1216         if (length == JMP_SHORTEST) {
1217                 g(ia64_insn(ctx, UNIT_B, IA64_B_BR21, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1218                 bundle = get_free_slot(ctx) - 1;
1219                 ctx->mcode_size += bundle;
1220                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1221                 ctx->mcode_size -= bundle;
1222         } else {
1223                 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1224                 mc = IA64_X_BRL;
1225                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1226                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1227         }
1228         return true;
1231 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
1233         uint64_t mc;
1234         unsigned bundle;
1235         unsigned reg = cget_one(ctx);
1236         if (unlikely(!reg_is_p(reg)))
1237                 goto invalid;
1238         switch (aux) {
1239                 case COND_NE:
1240                         break;
1241                 case COND_E:
1242                         reg ^= 1;
1243                         break;
1244                 default:
1245                         goto invalid;
1246         }
1247         if (likely(length == JMP_SHORTEST)) {
1248                 mc = IA64_B_BR21 | IA64_BR_DPNT;
1249                 mc |= bits_p(reg);
1250                 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1251                 bundle = get_free_slot(ctx) - 1;
1252                 ctx->mcode_size += bundle;
1253                 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
1254                 ctx->mcode_size -= bundle;
1255         } else {
1256                 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1257                 mc = IA64_X_BRL | IA64_BR_DPNT;
1258                 mc |= bits_p(reg);
1259                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1260                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
1261         }
1262         return true;
1263 invalid:
1264         internal(file_line, "cgen_jmp_reg: invalid arguments %x, %x, %x", reg, aux, length);
1267 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
1269         uint64_t mc;
1270         unsigned reg = cget_one(ctx);
1272         mc = IA64_I_MOVE_TO_BR;
1273         mc |= bits_gr(reg) << 13;
1274         mc |= bits_b(R_SCRATCH_B) << 6;
1275         g(ia64_insn(ctx, UNIT_I, mc, R_SCRATCH_B, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1277         mc = IA64_B_BR_JMP_INDIRECT;
1278         mc |= bits_b(R_SCRATCH_B) << 13;
1279         g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1280         return true;
1283 static uint64_t extract_bundle(uint8_t *ptr, unsigned bundle)
1285         uint64_t mc[2];
1286         memcpy(mc, ptr, 16);
1287         switch (bundle) {
1288                 case 0: return mc[0] >> 5 & 0x1ffffffffffULL;
1289                         break;
1290                 case 1: return mc[0] >> 46 | (mc[1] & 0x7fffffULL) << 18;
1291                         break;
1292                 case 2: return mc[1] >> 23;
1293                         break;
1294                 default:internal(file_line, "extract_bundle: invalid bundle %u", bundle);
1295         }
1298 static void insert_bundle(uint8_t *ptr, unsigned bundle, uint64_t instr)
1300         uint64_t mc[2];
1301         memcpy(mc, ptr, 16);
1302         switch (bundle) {
1303                 case 0: mc[0] = (mc[0] & ~(0x1ffffffffffULL << 5)) | instr << 5;
1304                         break;
1305                 case 1: mc[0] = (mc[0] & ~(-1ULL << 46)) | instr << 46;
1306                         mc[1] = (mc[1] & ~0x7fffffULL) | instr >> 18;
1307                         break;
1308                 case 2: mc[1] = (mc[1] & ~(-1ULL << 23)) | instr << 23;
1309                         break;
1310                 default:internal(file_line, "insert_bundle: invalid bundle %u", bundle);
1311         }
1312         memcpy(ptr, mc, 16);
1315 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1317         uint64_t mc;
1318         unsigned imm41;
1319         unsigned bundle = reloc->position & 3;
1320         size_t position = reloc->position & ~3;
1321         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 4) - (int64_t)(position >> 4);
1322         /*debug("relocation: position %lx, bundle %x, offset %lx, label %lx", reloc->position, bundle, offs, ctx->label_to_pos[reloc->label_id]);*/
1323         switch (reloc->length) {
1324                 case JMP_SHORTEST:
1325                         if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
1326                                 return false;
1327                         mc = extract_bundle(ctx->mcode + position, bundle);
1328                         mc &= ~0x011ffffe000ULL;
1329                         mc |= (offs & 0xfffffULL) << 13;
1330                         mc |= ((uint64_t)offs >> 20 & 1) << 36;
1331                         insert_bundle(ctx->mcode + position, bundle, mc);
1332                         return true;
1333                 case JMP_SHORT:
1334                         imm41 = extract_bundle(ctx->mcode + position, 1);
1335                         mc = extract_bundle(ctx->mcode + position, 2);
1336                         mc &= ~0x011ffffe000ULL;
1337                         mc |= (offs & 0xfffffULL) << 13;
1338                         imm41 &= ~0x1fffffffffcULL;
1339                         imm41 |= (offs >> 20 << 2) & 0x1fffffffffcULL;
1340                         mc |= ((uint64_t)offs >> 59 & 1) << 36;
1341                         insert_bundle(ctx->mcode + position, 1, imm41);
1342                         insert_bundle(ctx->mcode + position, 2, mc);
1343                         return true;
1344                 default:
1345                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1346         }
1347         return false;
1350 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1352         bool full;
1353         switch (insn_opcode(insn)) {
1354                 case INSN_ENTRY:
1355                         full = ia64_fill_bundle(ctx);
1356                         if (full)
1357                                 ctx->mcode_size += 16;
1358                         g(cgen_entry(ctx));
1359                         if (full)
1360                                 ctx->mcode_size -= 16;
1361                         return true;
1362                 case INSN_LABEL:
1363                         full = ia64_fill_bundle(ctx);
1364                         if (full)
1365                                 ctx->mcode_size += 16;
1366                         g(cgen_label(ctx));
1367                         if (full)
1368                                 ctx->mcode_size -= 16;
1369                         return true;
1370                 case INSN_RET:
1371                         g(cgen_ia64_ret(ctx));
1372                         g(ia64_purge_bundle(ctx));
1373                         return true;
1374                 case INSN_IA64_ALLOC:
1375                         g(cgen_ia64_alloc(ctx));
1376                         return true;
1377                 case INSN_IA64_DEALLOC:
1378                         g(cgen_ia64_dealloc(ctx));
1379                         return true;
1380                 case INSN_CALL_INDIRECT:
1381                         g(cgen_call_indirect(ctx));
1382                         return true;
1383                 case INSN_MOV:
1384                         g(cgen_mov(ctx, insn_op_size(insn)));
1385                         return true;
1386                 case INSN_MOVSX:
1387                         g(cgen_movsx(ctx, insn_op_size(insn)));
1388                         return true;
1389                 case INSN_CMP_DEST_REG:
1390                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1391                                 goto invalid_insn;
1392                         g(cgen_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
1393                         return true;
1394                 case INSN_TEST_DEST_REG:
1395                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1396                                 goto invalid_insn;
1397                         g(cgen_test_dest_reg(ctx, insn_aux(insn) & 63, insn_aux(insn) >> 6));
1398                         return true;
1399                 case INSN_ALU:
1400                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1401                                 goto invalid_insn;
1402                         g(cgen_alu(ctx, insn_aux(insn)));
1403                         return true;
1404                 case INSN_ALU1:
1405                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1406                                 goto invalid_insn;
1407                         g(cgen_alu1(ctx, insn_aux(insn)));
1408                         return true;
1409                 case INSN_ROT:
1410                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1411                                 goto invalid_insn;
1412                         g(cgen_rot(ctx, insn_aux(insn)));
1413                         return true;
1414                 case INSN_BTX:
1415                         g(cgen_btx(ctx, insn_aux(insn)));
1416                         return true;
1417                 case INSN_MOVR:
1418                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1419                                 goto invalid_insn;
1420                         g(cgen_movr(ctx, insn_aux(insn)));
1421                         return true;
1422                 case INSN_FP_CMP_DEST_REG:
1423                         g(cgen_fp_cmp_dest_reg(ctx, insn_aux(insn)));
1424                         return true;
1425                 case INSN_FP_ALU:
1426                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1427                         return true;
1428                 case INSN_FP_ALU1:
1429                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1430                         return true;
1431                 case INSN_FP_TO_INT64:
1432                         g(cgen_fp_to_int(ctx));
1433                         return true;
1434                 case INSN_FP_FROM_INT64:
1435                         g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1436                         return true;
1437                 case INSN_JMP:
1438                         g(cgen_jmp(ctx, insn_jump_size(insn)));
1439                         return true;
1440                 case INSN_JMP_REG:
1441                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1442                                 goto invalid_insn;
1443                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1444                         return true;
1445                 case INSN_JMP_INDIRECT:
1446                         g(cgen_jmp_indirect(ctx));
1447                         return true;
1448                 default:
1449                 invalid_insn:
1450                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
1451                         return false;
1452         }