x86-64: hack the ABI of cg_upcall_ipret_copy_variable_to_pointer
[ajla.git] / c2-ia64.inc
blob16be950deac4af6bde4e702aac6a13ff14e45d79
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                 if (reg_is_p(arg2[0])) {
574                         mc = IA64_A_ADD_IMM14;
575                         mc |= bits_gr(R_CG_SCRATCH) << 6;
576                         mc |= (uint64_t)1 << 13;
577                         mc |= bits_p(arg2[0]);
578                         g(ia64_insn(ctx, UNIT_A, mc, R_CG_SCRATCH, ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
580                         mc = IA64_A_ADD_IMM14;
581                         mc |= bits_gr(R_CG_SCRATCH) << 6;
582                         mc |= bits_p(arg2[0] ^ 1);
583                         g(ia64_insn(ctx, UNIT_A, mc, R_CG_SCRATCH, ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
585                         switch (size) {
586                                 case OP_SIZE_1: mc = IA64_M_ST1; break;
587                                 case OP_SIZE_2: mc = IA64_M_ST2; break;
588                                 case OP_SIZE_4: mc = IA64_M_ST4; break;
589                                 case OP_SIZE_8: mc = IA64_M_ST8; break;
590                                 default:        goto invalid;
591                         }
592                         mc |= bits_gr(R_CG_SCRATCH) << 13;
593                         mc |= bits_gr(arg1[1]) << 20;
594                         g(ia64_insn(ctx, UNIT_M, mc, ACCESS_MEMORY, ACCESS_NOTHING, arg1[1], R_CG_SCRATCH, ACCESS_NOTHING));
595                         return true;
596                 }
597         }
599 invalid:
600         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
601         return false;
604 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
606         uint64_t mc;
607         uint8_t *arg1 = ctx->code_position;
608         uint8_t *arg2 = arg1 + arg_size(*arg1);
609         ctx->code_position = arg2 + arg_size(*arg2);
611         if (likely(reg_is_gr(arg1[0])) && likely(reg_is_gr(arg2[0]))) {
612                 switch (size) {
613                         case OP_SIZE_1:
614                                 mc = IA64_I_SXT1;
615                                 break;
616                         case OP_SIZE_2:
617                                 mc = IA64_I_SXT2;
618                                 break;
619                         case OP_SIZE_4:
620                                 mc = IA64_I_SXT4;
621                                 break;
622                         case OP_SIZE_NATIVE:
623                                 mc = IA64_A_ADD_IMM14;
624                                 mc |= bits_gr(arg1[0]) << 6;
625                                 mc |= bits_gr(arg2[0]) << 20;
626                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
627                                 return true;
628                         default:
629                                 goto invalid;
630                 }
631                 mc |= bits_gr(arg1[0]) << 6;
632                 mc |= bits_gr(arg2[0]) << 20;
633                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
634                 return true;
635         }
637 invalid:
638         internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u", arg1[0], arg2[0], size);
639         return false;
642 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned cond)
644         uint64_t mc;
645         unsigned pred;
646         bool swap_preds = false, swap_regs = false;
647         uint8_t z = R_ZERO;
648         uint8_t *arg1 = ctx->code_position;
649         uint8_t *arg2 = arg1 + arg_size(*arg1);
650         uint8_t *arg3 = arg2 + arg_size(*arg2);
651         ctx->code_position = arg3 + arg_size(*arg3);
653         if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
654                 goto invalid;
656         pred = arg1[0];
658         if (arg3[0] == ARG_IMM) {
659                 int64_t imm = get_imm(&arg3[1]);
660                 if (likely(!imm)) {
661                         arg3 = &z;
662                         goto cmp_3reg;
663                 }
664                 if (unlikely(imm <= -0x80) || unlikely(imm >= 0x80))
665                         goto invalid;
666                 switch (cond) {
667                         case COND_AE:   mc = IA64_A_CMP_LTU_IMM8; imm--; break;
668                         case COND_B:    mc = IA64_A_CMP_LTU_IMM8; imm--; swap_preds = true; break;
669                         case COND_E:    mc = IA64_A_CMP_EQ_IMM8; break;
670                         case COND_NE:   mc = IA64_A_CMP_EQ_IMM8; swap_preds = true; break;
671                         case COND_BE:   mc = IA64_A_CMP_LTU_IMM8; swap_preds = true; break;
672                         case COND_A:    mc = IA64_A_CMP_LTU_IMM8; break;
673                         case COND_L:    mc = IA64_A_CMP_LT_IMM8; imm--; swap_preds = true; break;
674                         case COND_GE:   mc = IA64_A_CMP_LT_IMM8; imm--; break;
675                         case COND_LE:   mc = IA64_A_CMP_LT_IMM8; swap_preds = true; break;
676                         case COND_G:    mc = IA64_A_CMP_LT_IMM8; break;
677                         default:        goto invalid;
678                 }
680                 if (swap_preds)
681                         pred ^= 1;
683                 if (op_size == OP_SIZE_4)
684                         mc |= IA64_A_CMP4;
686                 mc |= (imm & 0x7f) << 13;
687                 mc |= ((uint64_t)imm >> 7 & 1) << 36;
688                 mc |= bits_gr(arg2[0]) << 20;
689                 mc |= bits_p(pred) << 6;
690                 mc |= bits_p(pred ^ 1) << 27;
691                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
692                 return true;
693         }
695         if (!reg_is_gr(arg3[0]))
696                 goto invalid;
698 cmp_3reg:
699         switch (cond) {
700                 case COND_B:    mc = IA64_A_CMP_LTU; break;
701                 case COND_AE:   mc = IA64_A_CMP_LTU; swap_preds = true; break;
702                 case COND_E:    mc = IA64_A_CMP_EQ; break;
703                 case COND_NE:   mc = IA64_A_CMP_EQ; swap_preds = true; break;
704                 case COND_BE:   mc = IA64_A_CMP_LTU; swap_regs = true; swap_preds = true; break;
705                 case COND_A:    mc = IA64_A_CMP_LTU; swap_regs = true; break;
706                 case COND_L:    mc = IA64_A_CMP_LT; break;
707                 case COND_GE:   mc = IA64_A_CMP_LT; swap_preds = true; break;
708                 case COND_LE:   mc = IA64_A_CMP_LT; swap_regs = true; swap_preds = true; break;
709                 case COND_G:    mc = IA64_A_CMP_LT; swap_regs = true; break;
710                 default:        goto invalid;
711         }
713         if (swap_regs) {
714                 uint8_t *argx = arg2;
715                 arg2 = arg3;
716                 arg3 = argx;
717         }
719         if (swap_preds)
720                 pred ^= 1;
722         if (op_size == OP_SIZE_4)
723                 mc |= IA64_A_CMP4;
725         mc |= bits_gr(arg2[0]) << 13;
726         mc |= bits_gr(arg3[0]) << 20;
727         mc |= bits_p(pred) << 6;
728         mc |= bits_p(pred ^ 1) << 27;
729         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], arg3[0], ACCESS_NOTHING));
730         return true;
732 invalid:
733         internal(file_line, "cgen_cmp_dest_reg: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
734         return false;
737 static bool attr_w cgen_test_dest_reg(struct codegen_context *ctx, unsigned bit, bool jnz)
739         uint64_t mc;
740         unsigned pred;
741         uint8_t *arg1 = ctx->code_position;
742         uint8_t *arg2 = arg1 + arg_size(*arg1);
743         ctx->code_position = arg2 + arg_size(*arg2);
745         if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
746                 goto invalid;
748         pred = arg1[0];
750         if (jnz)
751                 pred ^= 1;
753         mc = IA64_I_TBIT;
754         mc |= (uint64_t)bit << 14;
755         mc |= bits_gr(arg2[0]) << 20;
756         mc |= bits_p(pred) << 6;
757         mc |= bits_p(pred ^ 1) << 27;
758         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], arg1[0] ^ 1, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
759         return true;
761 invalid:
762         internal(file_line, "cgen_test_dest_reg: invalid arguments %02x, %02x", arg1[0], arg2[0]);
763         return false;
766 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned alu)
768         uint64_t mc;
769         uint8_t *arg1 = ctx->code_position;
770         uint8_t *arg2 = arg1 + arg_size(*arg1);
771         uint8_t *arg3 = arg2 + arg_size(*arg2);
772         ctx->code_position = arg3 + arg_size(*arg3);
774         if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
775                 uint8_t *arg_swp = arg3;
776                 arg3 = arg2;
777                 arg2 = arg_swp;
778         }
780         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
781                 goto invalid;
783 gr_gr_gr:
784         if (reg_is_gr(arg3[0])) {
785                 mc = IA64_A_ALU;
786                 switch (alu) {
787                         case ALU_ADD:   mc |= IA64_A_ALU_ADD; break;
788                         case ALU_SUB:   mc |= IA64_A_ALU_SUB; break;
789                         case ALU_AND:   mc |= IA64_A_ALU_AND; break;
790                         case ALU_ANDN:  mc |= IA64_A_ALU_ANDCM; break;
791                         case ALU_OR:    mc |= IA64_A_ALU_OR; break;
792                         case ALU_XOR:   mc |= IA64_A_ALU_XOR; break;
793                         default:        goto invalid;
794                 }
795                 mc |= bits_gr(arg1[0]) << 6;
796                 mc |= bits_gr(arg2[0]) << 13;
797                 mc |= bits_gr(arg3[0]) << 20;
798                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
799                 return true;
800         }
802         if (arg3[0] == ARG_SHIFTED_REGISTER && (arg3[1] & ARG_SHIFT_MODE) == ARG_SHIFT_LSL) {
803                 unsigned amount = arg3[1] & ARG_SHIFT_AMOUNT;
804                 if (!amount) {
805                         arg3 += 2;
806                         goto gr_gr_gr;
807                 }
808                 if (unlikely(amount > 4))
809                         goto invalid;
810                 mc = IA64_A_SHLADD;
811                 mc |= bits_gr(arg1[0]) << 6;
812                 mc |= bits_gr(arg3[2]) << 13;
813                 mc |= bits_gr(arg2[0]) << 20;
814                 mc |= (amount - 1) << 27;
815                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[2], ACCESS_NOTHING));
816                 return true;
817         }
819         if (arg3[0] == ARG_IMM) {
820                 int64_t imm = get_imm(&arg3[1]);
821                 if (alu == ALU_SUB) {
822                         imm = -(uint64_t)imm;
823                         alu = ALU_ADD;
824                 }
825                 if (alu == ALU_ADD) {
826                         if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
827                                 goto invalid;
828                         mc = IA64_A_ADD_IMM14;
829                         mc |= bits_gr(arg1[0]) << 6;
830                         mc |= bits_gr(arg2[0]) << 20;
831                         mc |= (imm & 0x7f) << 13;
832                         mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
833                         mc |= ((uint64_t)imm >> 13 & 1) << 36;
834                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
835                         return true;
836                 } else if (alu == ALU_AND || alu == ALU_OR || alu == ALU_XOR) {
837                         if (unlikely(imm < -0x80) || unlikely(imm >= 0x80))
838                                 goto invalid;
839                         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);
840                         mc |= bits_gr(arg1[0]) << 6;
841                         mc |= bits_gr(arg2[0]) << 20;
842                         mc |= (imm & 0x7f) << 13;
843                         mc |= ((uint64_t)imm >> 7 & 1) << 36;
844                         g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
845                         return true;
846                 } else {
847                         goto invalid;
848                 }
849         }
851 invalid:
852         internal(file_line, "cgen_alu: invalid arguments %u, %02x, %02x, %02x", alu, arg1[0], arg2[0], arg3[0]);
853         return false;
856 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned alu)
858         uint64_t mc;
859         uint8_t *arg1 = ctx->code_position;
860         uint8_t *arg2 = arg1 + arg_size(*arg1);
861         ctx->code_position = arg2 + arg_size(*arg2);
863         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
864                 goto invalid;
867         switch (alu) {
868                 case ALU1_NOT:  mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_ANDCM;
869                                 mc |= bits_gr(arg1[0]) << 6;
870                                 mc |= bits_gr(arg2[0]) << 20;
871                                 mc |= 0x7fULL << 13;
872                                 mc |= 0x1ULL << 36;
873                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
874                                 return true;
875                 case ALU1_NEG:  mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_SUB;
876                                 mc |= bits_gr(arg1[0]) << 6;
877                                 mc |= bits_gr(arg2[0]) << 20;
878                                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
879                                 return true;
880                 case ALU1_BSWAP:mc = IA64_I_MUX1_REV;
881                                 mc |= bits_gr(arg1[0]) << 6;
882                                 mc |= bits_gr(arg1[1]) << 13;
883                                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
884                                 return true;
885                 case ALU1_POPCNT:
886                                 mc = IA64_I_POPCNT;
887                                 mc |= bits_gr(arg1[0]) << 6;
888                                 mc |= bits_gr(arg2[0]) << 20;
889                                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
890                                 return true;
891                 default:        goto invalid;
892         }
894 invalid:
895         internal(file_line, "cgen_alu1: invalid arguments %u, %02x, %02x", alu, arg1[0], arg2[0]);
896         return false;
900 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned rot)
902         uint64_t mc;
903         uint8_t *arg1 = ctx->code_position;
904         uint8_t *arg2 = arg1 + arg_size(*arg1);
905         uint8_t *arg3 = arg2 + arg_size(*arg2);
906         ctx->code_position = arg3 + arg_size(*arg3);
908         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
909                 goto invalid;
911         if (arg3[0] == ARG_IMM) {
912                 uint64_t pos = get_imm(&arg3[1]) & 63;
913                 uint64_t len = 64 - pos - 1;
914                 switch (rot) {
915                         case ROT_SHL:   mc = IA64_I_DEP_Z;
916                                         mc |= bits_gr(arg1[0]) << 6;
917                                         mc |= bits_gr(arg2[0]) << 13;
918                                         mc |= (pos ^ 0x3f) << 20;
919                                         mc |= len << 27;
920                                         break;
921                         case ROT_SHR:   mc = IA64_I_EXTR_U;
922                                         mc |= bits_gr(arg1[0]) << 6;
923                                         mc |= pos << 14;
924                                         mc |= bits_gr(arg2[0]) << 20;
925                                         mc |= len << 27;
926                                         break;
927                         case ROT_SAR:   mc = IA64_I_EXTR;
928                                         mc |= bits_gr(arg1[0]) << 6;
929                                         mc |= pos << 14;
930                                         mc |= bits_gr(arg2[0]) << 20;
931                                         mc |= len << 27;
932                                         break;
933                         default:        goto invalid;
934                 }
935                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
936                 return true;
937         }
939         if (reg_is_gr(arg3[0])) {
940                 switch (rot) {
941                         case ROT_SHL:   mc = IA64_I_SHL;
942                                         mc |= bits_gr(arg1[0]) << 6;
943                                         mc |= bits_gr(arg2[0]) << 13;
944                                         mc |= bits_gr(arg3[0]) << 20;
945                                         break;
946                         case ROT_SHR:   mc = IA64_I_SHR_U;
947                                         mc |= bits_gr(arg1[0]) << 6;
948                                         mc |= bits_gr(arg3[0]) << 13;
949                                         mc |= bits_gr(arg2[0]) << 20;
950                                         break;
951                         case ROT_SAR:   mc = IA64_I_SHR;
952                                         mc |= bits_gr(arg1[0]) << 6;
953                                         mc |= bits_gr(arg3[0]) << 13;
954                                         mc |= bits_gr(arg2[0]) << 20;
955                                         break;
956                         default:        goto invalid;
957                 }
958                 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
959                 return true;
960         }
962 invalid:
963         internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], rot);
964         return false;
967 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
969         uint64_t mc;
970         int64_t imm;
971         uint8_t *arg1 = ctx->code_position;
972         uint8_t *arg2 = arg1 + arg_size(*arg1);
973         uint8_t *arg3 = arg2 + arg_size(*arg2);
974         ctx->code_position = arg3 + arg_size(*arg3);
975         if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])) || unlikely(arg3[0] != ARG_IMM))
976                 goto invalid;
978         imm = get_imm(&arg3[1]) & 0x3f;
980         mc = IA64_I_DEP_IMM;
982         switch (alu) {
983                 case BTX_BTS:   mc |= 1ULL << 36;
984                                 break;
985                 case BTX_BTR:   break;
986                 default:        goto invalid;
987         }
989         mc |= bits_gr(arg1[0]) << 6;
990         mc |= bits_gr(arg2[0]) << 20;
991         mc |= 0ULL << 27;
992         mc |= (imm ^ 0x3f) << 14;
994         g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
995         return true;
997 invalid:
998         internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
999         return false;
1002 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
1004         uint64_t mc;
1005         unsigned pred;
1006         uint8_t *arg1 = ctx->code_position;
1007         uint8_t *arg2 = arg1 + arg_size(*arg1);
1008         uint8_t *arg3 = arg2 + arg_size(*arg2);
1009         uint8_t *arg4 = arg3 + arg_size(*arg3);
1010         ctx->code_position = arg4 + arg_size(*arg4);
1011         if (unlikely(arg1[0] != arg2[0]) || unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_p(arg3[0])))
1012                 goto invalid;
1014         pred = arg3[0];
1015         switch (aux) {
1016                 case COND_E:    pred ^= 1; break;
1017                 case COND_NE:   break;
1018                 default:        goto invalid;
1019         }
1021         if (arg4[0] == ARG_IMM) {
1022                 int64_t imm = get_imm(&arg4[1]);
1023                 if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
1024                         goto invalid;
1025                 mc = IA64_A_ADD_IMM14;
1026                 mc |= bits_gr(arg1[0]) << 6;
1027                 mc |= (imm & 0x7f) << 13;
1028                 mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
1029                 mc |= ((uint64_t)imm >> 13 & 1) << 36;
1030                 mc |= bits_p(pred);
1031                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1032                 return true;
1033         }
1035         if (reg_is_gr(arg4[0])) {
1036                 mc = IA64_A_ADD_IMM14;
1037                 mc |= bits_gr(arg1[0]) << 6;
1038                 mc |= bits_gr(arg4[0]) << 20;
1039                 mc |= bits_p(pred);
1040                 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], arg4[0]));
1041                 return true;
1042         }
1044 invalid:
1045         internal(file_line, "cgen_movr: invalid arguments %02x, %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], arg4[0], aux);
1046         return false;
1049 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
1051         uint64_t mc;
1052         unsigned pred;
1053         bool swap_preds = false, swap_regs = false;
1054         uint8_t *arg1 = ctx->code_position;
1055         uint8_t *arg2 = arg1 + arg_size(*arg1);
1056         uint8_t *arg3 = arg2 + arg_size(*arg2);
1057         ctx->code_position = arg3 + arg_size(*arg3);
1059         pred = arg1[0];
1060         mc = IA64_F_FCMP;
1061         switch (aux) {
1062                 case FP_COND_P: mc |= IA64_F_FCMP_UNORD; break;
1063                 case FP_COND_NP:mc |= IA64_F_FCMP_UNORD; swap_preds = true; break;
1064                 case FP_COND_E: mc |= IA64_F_FCMP_EQ; break;
1065                 case FP_COND_NE:mc |= IA64_F_FCMP_EQ; swap_preds = true; break;
1066                 case FP_COND_A: mc |= IA64_F_FCMP_LT; swap_regs = true; break;
1067                 case FP_COND_BE:mc |= IA64_F_FCMP_LE; break;
1068                 case FP_COND_B: mc |= IA64_F_FCMP_LT; break;
1069                 case FP_COND_AE:mc |= IA64_F_FCMP_LE; swap_regs = true; break;
1070         }
1072         if (swap_regs) {
1073                 uint8_t *argx = arg2;
1074                 arg2 = arg3;
1075                 arg3 = argx;
1076         }
1078         if (swap_preds)
1079                 pred ^= 1;
1081         mc |= bits_fp(arg2[0]) << 13;
1082         mc |= bits_fp(arg3[0]) << 20;
1083         mc |= bits_p(pred) << 6;
1084         mc |= bits_p(pred ^ 1) << 27;
1085         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1086         return true;
1089 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1091         uint64_t mc, f1, f2, f3, f4;
1092         uint8_t *arg1 = ctx->code_position;
1093         uint8_t *arg2 = arg1 + arg_size(*arg1);
1094         uint8_t *arg3 = arg2 + arg_size(*arg2);
1095         ctx->code_position = arg3 + arg_size(*arg3);
1096         switch (aux) {
1097                 case FP_ALU_ADD:
1098                         mc = IA64_F_FMA;
1099                         f1 = bits_fp(arg1[0]);
1100                         f2 = bits_fp(arg3[0]);
1101                         f3 = bits_fp(arg2[0]);
1102                         f4 = bits_fp(FR_ONE);
1103                         break;
1104                 case FP_ALU_SUB:
1105                         mc = IA64_F_FMS;
1106                         f1 = bits_fp(arg1[0]);
1107                         f2 = bits_fp(arg3[0]);
1108                         f3 = bits_fp(arg2[0]);
1109                         f4 = bits_fp(FR_ONE);
1110                         break;
1111                 case FP_ALU_MUL:
1112                         mc = IA64_F_FMA;
1113                         f1 = bits_fp(arg1[0]);
1114                         f2 = bits_fp(FR_ZERO);
1115                         f3 = bits_fp(arg2[0]);
1116                         f4 = bits_fp(arg3[0]);
1117                         break;
1118                 default:
1119                         goto invalid;
1120         }
1121         switch (op_size) {
1122                 case OP_SIZE_4:
1123                         mc |= IA64_F_FMA_S;
1124                         break;
1125                 case OP_SIZE_8:
1126                         mc |= IA64_F_FMA_D;
1127                         break;
1128                 case OP_SIZE_10:
1129                         mc |= IA64_F_FMA_E;
1130                         break;
1131                 default:
1132                         goto invalid;
1133         }
1134         mc |= f1 << 6;
1135         mc |= f2 << 13;
1136         mc |= f3 << 20;
1137         mc |= f4 << 27;
1138         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1139         return true;
1141 invalid:
1142         internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, arg1[0], arg2[0], arg3[0]);
1143         return false;
1146 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1148         uint64_t mc;
1149         uint8_t *arg1 = ctx->code_position;
1150         uint8_t *arg2 = arg1 + arg_size(*arg1);
1151         ctx->code_position = arg2 + arg_size(*arg2);
1152         switch (aux) {
1153                 case FP_ALU1_NEG:
1154                         mc = IA64_F_FMERGE_NS;
1155                         mc |= bits_fp(arg1[0]) << 6;
1156                         mc |= bits_fp(arg2[0]) << 13;
1157                         mc |= bits_fp(arg2[0]) << 20;
1158                         break;
1159                 default:
1160                         goto invalid;
1161         }
1162         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1163         return true;
1165 invalid:
1166         internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, arg1[0], arg2[0]);
1167         return false;
1170 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx)
1172         uint64_t mc;
1173         uint8_t *arg1 = ctx->code_position;
1174         uint8_t *arg2 = arg1 + arg_size(*arg1);
1175         ctx->code_position = arg2 + arg_size(*arg2);
1177         mc = IA64_F_FCVT_FX_TRUNC;
1178         mc |= bits_fp(arg1[0]) << 6;
1179         mc |= bits_fp(arg2[0]) << 13;
1180         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1181         return true;
1184 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
1186         uint64_t mc;
1187         uint8_t *arg1 = ctx->code_position;
1188         uint8_t *arg2 = arg1 + arg_size(*arg1);
1189         ctx->code_position = arg2 + arg_size(*arg2);
1191         mc = IA64_F_FCVT_XF;
1192         mc |= bits_fp(arg1[0]) << 6;
1193         mc |= bits_fp(arg2[0]) << 13;
1194         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1196         mc = IA64_F_FMA;
1197         switch (fp_op_size) {
1198                 case OP_SIZE_4:
1199                         mc |= IA64_F_FMA_S;
1200                         break;
1201                 case OP_SIZE_8:
1202                         mc |= IA64_F_FMA_D;
1203                         break;
1204                 case OP_SIZE_10:
1205                         goto skip_norm;
1206                 default:
1207                         goto invalid;
1208         }
1209         mc |= bits_fp(arg1[0]) << 6;
1210         mc |= bits_fp(FR_ZERO) << 13;
1211         mc |= bits_fp(arg1[0]) << 20;
1212         mc |= bits_fp(FR_ONE) << 27;
1213         g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING));
1214 skip_norm:
1215         return true;
1217 invalid:
1218         internal(file_line, "cgen_fp_from_int: invalid arguments %u, %02x, %02x", fp_op_size, arg1[0], arg2[0]);
1219         return false;
1222 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
1224         uint64_t mc;
1225         unsigned bundle;
1226         if (length == JMP_SHORTEST) {
1227                 g(ia64_insn(ctx, UNIT_B, IA64_B_BR21, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1228                 bundle = get_free_slot(ctx) - 1;
1229                 ctx->mcode_size += bundle;
1230                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1231                 ctx->mcode_size -= bundle;
1232         } else {
1233                 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1234                 mc = IA64_X_BRL;
1235                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1236                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1237         }
1238         return true;
1241 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
1243         uint64_t mc;
1244         unsigned bundle;
1245         unsigned reg = cget_one(ctx);
1246         if (unlikely(!reg_is_p(reg)))
1247                 goto invalid;
1248         switch (aux) {
1249                 case COND_NE:
1250                         break;
1251                 case COND_E:
1252                         reg ^= 1;
1253                         break;
1254                 default:
1255                         goto invalid;
1256         }
1257         if (likely(length == JMP_SHORTEST)) {
1258                 mc = IA64_B_BR21 | IA64_BR_DPNT;
1259                 mc |= bits_p(reg);
1260                 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1261                 bundle = get_free_slot(ctx) - 1;
1262                 ctx->mcode_size += bundle;
1263                 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
1264                 ctx->mcode_size -= bundle;
1265         } else {
1266                 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1267                 mc = IA64_X_BRL | IA64_BR_DPNT;
1268                 mc |= bits_p(reg);
1269                 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1270                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
1271         }
1272         return true;
1273 invalid:
1274         internal(file_line, "cgen_jmp_reg: invalid arguments %x, %x, %x", reg, aux, length);
1277 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
1279         uint64_t mc;
1280         unsigned reg = cget_one(ctx);
1282         mc = IA64_I_MOVE_TO_BR;
1283         mc |= bits_gr(reg) << 13;
1284         mc |= bits_b(R_SCRATCH_B) << 6;
1285         g(ia64_insn(ctx, UNIT_I, mc, R_SCRATCH_B, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1287         mc = IA64_B_BR_JMP_INDIRECT;
1288         mc |= bits_b(R_SCRATCH_B) << 13;
1289         g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1290         return true;
1293 static uint64_t extract_bundle(uint8_t *ptr, unsigned bundle)
1295         uint64_t mc[2];
1296         memcpy(mc, ptr, 16);
1297         switch (bundle) {
1298                 case 0: return mc[0] >> 5 & 0x1ffffffffffULL;
1299                         break;
1300                 case 1: return mc[0] >> 46 | (mc[1] & 0x7fffffULL) << 18;
1301                         break;
1302                 case 2: return mc[1] >> 23;
1303                         break;
1304                 default:internal(file_line, "extract_bundle: invalid bundle %u", bundle);
1305         }
1308 static void insert_bundle(uint8_t *ptr, unsigned bundle, uint64_t instr)
1310         uint64_t mc[2];
1311         memcpy(mc, ptr, 16);
1312         switch (bundle) {
1313                 case 0: mc[0] = (mc[0] & ~(0x1ffffffffffULL << 5)) | instr << 5;
1314                         break;
1315                 case 1: mc[0] = (mc[0] & ~(-1ULL << 46)) | instr << 46;
1316                         mc[1] = (mc[1] & ~0x7fffffULL) | instr >> 18;
1317                         break;
1318                 case 2: mc[1] = (mc[1] & ~(-1ULL << 23)) | instr << 23;
1319                         break;
1320                 default:internal(file_line, "insert_bundle: invalid bundle %u", bundle);
1321         }
1322         memcpy(ptr, mc, 16);
1325 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1327         uint64_t mc;
1328         unsigned imm41;
1329         unsigned bundle = reloc->position & 3;
1330         size_t position = reloc->position & ~3;
1331         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 4) - (int64_t)(position >> 4);
1332         /*debug("relocation: position %lx, bundle %x, offset %lx, label %lx", reloc->position, bundle, offs, ctx->label_to_pos[reloc->label_id]);*/
1333         switch (reloc->length) {
1334                 case JMP_SHORTEST:
1335                         if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
1336                                 return false;
1337                         mc = extract_bundle(ctx->mcode + position, bundle);
1338                         mc &= ~0x011ffffe000ULL;
1339                         mc |= (offs & 0xfffffULL) << 13;
1340                         mc |= ((uint64_t)offs >> 20 & 1) << 36;
1341                         insert_bundle(ctx->mcode + position, bundle, mc);
1342                         return true;
1343                 case JMP_SHORT:
1344                         imm41 = extract_bundle(ctx->mcode + position, 1);
1345                         mc = extract_bundle(ctx->mcode + position, 2);
1346                         mc &= ~0x011ffffe000ULL;
1347                         mc |= (offs & 0xfffffULL) << 13;
1348                         imm41 &= ~0x1fffffffffcULL;
1349                         imm41 |= (offs >> 20 << 2) & 0x1fffffffffcULL;
1350                         mc |= ((uint64_t)offs >> 59 & 1) << 36;
1351                         insert_bundle(ctx->mcode + position, 1, imm41);
1352                         insert_bundle(ctx->mcode + position, 2, mc);
1353                         return true;
1354                 default:
1355                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1356         }
1357         return false;
1360 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1362         bool full;
1363         switch (insn_opcode(insn)) {
1364                 case INSN_ENTRY:
1365                         full = ia64_fill_bundle(ctx);
1366                         if (full)
1367                                 ctx->mcode_size += 16;
1368                         g(cgen_entry(ctx));
1369                         if (full)
1370                                 ctx->mcode_size -= 16;
1371                         return true;
1372                 case INSN_LABEL:
1373                         full = ia64_fill_bundle(ctx);
1374                         if (full)
1375                                 ctx->mcode_size += 16;
1376                         g(cgen_label(ctx));
1377                         if (full)
1378                                 ctx->mcode_size -= 16;
1379                         return true;
1380                 case INSN_RET:
1381                         g(cgen_ia64_ret(ctx));
1382                         g(ia64_purge_bundle(ctx));
1383                         return true;
1384                 case INSN_IA64_ALLOC:
1385                         g(cgen_ia64_alloc(ctx));
1386                         return true;
1387                 case INSN_IA64_DEALLOC:
1388                         g(cgen_ia64_dealloc(ctx));
1389                         return true;
1390                 case INSN_CALL_INDIRECT:
1391                         g(cgen_call_indirect(ctx));
1392                         return true;
1393                 case INSN_MOV:
1394                         g(cgen_mov(ctx, insn_op_size(insn)));
1395                         return true;
1396                 case INSN_MOVSX:
1397                         g(cgen_movsx(ctx, insn_op_size(insn)));
1398                         return true;
1399                 case INSN_CMP_DEST_REG:
1400                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1401                                 goto invalid_insn;
1402                         g(cgen_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
1403                         return true;
1404                 case INSN_TEST_DEST_REG:
1405                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1406                                 goto invalid_insn;
1407                         g(cgen_test_dest_reg(ctx, insn_aux(insn) & 63, insn_aux(insn) >> 6));
1408                         return true;
1409                 case INSN_ALU:
1410                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1411                                 goto invalid_insn;
1412                         g(cgen_alu(ctx, insn_aux(insn)));
1413                         return true;
1414                 case INSN_ALU1:
1415                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1416                                 goto invalid_insn;
1417                         g(cgen_alu1(ctx, insn_aux(insn)));
1418                         return true;
1419                 case INSN_ROT:
1420                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1421                                 goto invalid_insn;
1422                         g(cgen_rot(ctx, insn_aux(insn)));
1423                         return true;
1424                 case INSN_BTX:
1425                         g(cgen_btx(ctx, insn_aux(insn)));
1426                         return true;
1427                 case INSN_MOVR:
1428                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1429                                 goto invalid_insn;
1430                         g(cgen_movr(ctx, insn_aux(insn)));
1431                         return true;
1432                 case INSN_FP_CMP_DEST_REG:
1433                         g(cgen_fp_cmp_dest_reg(ctx, insn_aux(insn)));
1434                         return true;
1435                 case INSN_FP_ALU:
1436                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1437                         return true;
1438                 case INSN_FP_ALU1:
1439                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1440                         return true;
1441                 case INSN_FP_TO_INT64:
1442                         g(cgen_fp_to_int(ctx));
1443                         return true;
1444                 case INSN_FP_FROM_INT64:
1445                         g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1446                         return true;
1447                 case INSN_JMP:
1448                         g(cgen_jmp(ctx, insn_jump_size(insn)));
1449                         return true;
1450                 case INSN_JMP_REG:
1451                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1452                                 goto invalid_insn;
1453                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1454                         return true;
1455                 case INSN_JMP_INDIRECT:
1456                         g(cgen_jmp_indirect(ctx));
1457                         return true;
1458                 default:
1459                 invalid_insn:
1460                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
1461                         return false;
1462         }