2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
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
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.
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/>.
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
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,
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,
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,
162 UNIT_M | UNIT_F << 8 | UNIT_B << 16,
163 UNIT_M | UNIT_F << 8 | UNIT_B << 16 | STOP_23,
168 #define ACCESS_MEMORY 0xfe
169 #define ACCESS_NOTHING 0xff
171 static void new_bundle(struct codegen_context *ctx)
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;
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)
192 static bool test_mask(uint64_t mask[4], uint8_t bit)
194 if (bit == ACCESS_NOTHING)
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)
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)
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)) {
220 if (ctx->a.insn_stops[j] != (tmpl >> (24 + j) & 1)) {
230 static uint64_t get_nop(unsigned 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);
244 static unsigned get_free_slot(struct codegen_context *ctx)
247 while (slot > 0 && ctx->a.insns[slot - 1] == -1ULL)
252 static bool attr_w ia64_purge_bundle(struct codegen_context *ctx)
257 if (!get_free_slot(ctx))
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;
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;
277 static bool ia64_fill_bundle(struct codegen_context *ctx)
281 if (!get_free_slot(ctx))
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;
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);*/
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;
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;
319 g(ia64_purge_bundle(ctx));
327 ctx->a.insn_units[slot] = unit;
328 if (!get_possible_templates(ctx)) {
329 ctx->a.insn_units[slot] = 0xff;
331 if (unlikely(slot == 3)) {
332 g(ia64_purge_bundle(ctx));
337 ctx->a.insns[slot] = mc;
338 set_mask(ctx->a.wr_mask, wr1);
339 set_mask(ctx->a.wr_mask, wr2);
343 static bool attr_w cgen_ia64_ret(struct codegen_context *ctx)
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));
350 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_MEMORY, ACCESS_NOTHING, ACCESS_NOTHING));
354 static bool attr_w cgen_ia64_alloc(struct codegen_context *ctx)
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);
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));
370 static bool attr_w cgen_ia64_dealloc(struct codegen_context *ctx)
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));
381 static bool attr_w cgen_call_indirect(struct codegen_context *ctx)
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));
392 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
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])) {
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));
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));
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));
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));
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));
455 if (arg2[0] == ARG_ADDRESS_1) {
456 imm = get_imm(&arg2[2]);
457 if (unlikely(imm != 0))
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;
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));
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));
483 mc = (imm & 0x7fffffffffc00000ULL) >> 22;
484 g(ia64_insn(ctx, UNIT_L, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
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));
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));
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));
513 if (arg2[0] == ARG_ADDRESS_1) {
514 imm = get_imm(&arg2[2]);
515 if (unlikely(imm != 0))
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;
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));
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));
538 if (arg1[0] == ARG_ADDRESS_1) {
539 imm = get_imm(&arg1[2]);
540 if (unlikely(imm != 0))
542 if (arg2[0] == ARG_IMM) {
543 imm = get_imm(&arg2[1]);
544 if (unlikely(imm != 0))
548 if (reg_is_gr(arg2[0])) {
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;
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));
561 if (reg_is_fp(arg2[0])) {
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;
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));
576 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
580 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
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]))) {
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));
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));
614 internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u", arg1[0], arg2[0], size);
618 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned cond)
622 bool swap_preds = false, swap_regs = false;
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])))
634 if (arg3[0] == ARG_IMM) {
635 int64_t imm = get_imm(&arg3[1]);
640 if (unlikely(imm <= -0x80) || unlikely(imm >= 0x80))
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;
659 if (op_size == OP_SIZE_4)
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));
671 if (!reg_is_gr(arg3[0]))
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;
690 uint8_t *argx = arg2;
698 if (op_size == OP_SIZE_4)
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));
709 internal(file_line, "cgen_cmp_dest_reg: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
713 static bool attr_w cgen_test_dest_reg(struct codegen_context *ctx, unsigned bit, bool jnz)
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])))
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));
738 internal(file_line, "cgen_test_dest_reg: invalid arguments %02x, %02x", arg1[0], arg2[0]);
742 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned alu)
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;
756 if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
760 if (reg_is_gr(arg3[0])) {
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;
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));
778 if (arg3[0] == ARG_SHIFTED_REGISTER && (arg3[1] & ARG_SHIFT_MODE) == ARG_SHIFT_LSL) {
779 unsigned amount = arg3[1] & ARG_SHIFT_AMOUNT;
784 if (unlikely(amount > 4))
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));
795 if (arg3[0] == ARG_IMM) {
796 int64_t imm = get_imm(&arg3[1]);
797 if (alu == ALU_SUB) {
798 imm = -(uint64_t)imm;
801 if (alu == ALU_ADD) {
802 if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
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));
812 } else if (alu == ALU_AND || alu == ALU_OR || alu == ALU_XOR) {
813 if (unlikely(imm < -0x80) || unlikely(imm >= 0x80))
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));
828 internal(file_line, "cgen_alu: invalid arguments %u, %02x, %02x, %02x", alu, arg1[0], arg2[0], arg3[0]);
832 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned alu)
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])))
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;
849 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
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));
856 case ALU1_INC: mc = IA64_A_ADD_IMM14;
857 mc |= bits_gr(arg1[0]) << 6;
858 mc |= bits_gr(arg2[0]) << 20;
860 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
862 case ALU1_DEC: mc = IA64_A_ADD_IMM14;
863 mc |= bits_gr(arg1[0]) << 6;
864 mc |= bits_gr(arg2[0]) << 20;
868 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
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));
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));
881 default: goto invalid;
885 internal(file_line, "cgen_alu1: invalid arguments %u, %02x, %02x", alu, arg1[0], arg2[0]);
890 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned rot)
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])))
901 if (arg3[0] == ARG_IMM) {
902 uint64_t pos = get_imm(&arg3[1]) & 63;
903 uint64_t len = 64 - pos - 1;
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;
911 case ROT_SHR: mc = IA64_I_EXTR_U;
912 mc |= bits_gr(arg1[0]) << 6;
914 mc |= bits_gr(arg2[0]) << 20;
917 case ROT_SAR: mc = IA64_I_EXTR;
918 mc |= bits_gr(arg1[0]) << 6;
920 mc |= bits_gr(arg2[0]) << 20;
923 default: goto invalid;
925 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
929 if (reg_is_gr(arg3[0])) {
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;
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;
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;
946 default: goto invalid;
948 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
953 internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], rot);
957 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
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))
968 imm = get_imm(&arg3[1]) & 0x3f;
973 case BTX_BTS: mc |= 1ULL << 36;
976 default: goto invalid;
979 mc |= bits_gr(arg1[0]) << 6;
980 mc |= bits_gr(arg2[0]) << 20;
982 mc |= (imm ^ 0x3f) << 14;
984 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
988 internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
992 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
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])))
1006 case COND_E: pred ^= 1; break;
1007 case COND_NE: break;
1008 default: goto invalid;
1011 if (arg4[0] == ARG_IMM) {
1012 int64_t imm = get_imm(&arg4[1]);
1013 if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
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;
1021 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
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;
1030 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], arg4[0]));
1035 internal(file_line, "cgen_movr: invalid arguments %02x, %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], arg4[0], aux);
1039 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
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);
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;
1063 uint8_t *argx = arg2;
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));
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);
1089 f1 = bits_fp(arg1[0]);
1090 f2 = bits_fp(arg3[0]);
1091 f3 = bits_fp(arg2[0]);
1092 f4 = bits_fp(FR_ONE);
1096 f1 = bits_fp(arg1[0]);
1097 f2 = bits_fp(arg3[0]);
1098 f3 = bits_fp(arg2[0]);
1099 f4 = bits_fp(FR_ONE);
1103 f1 = bits_fp(arg1[0]);
1104 f2 = bits_fp(FR_ZERO);
1105 f3 = bits_fp(arg2[0]);
1106 f4 = bits_fp(arg3[0]);
1128 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1132 internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, arg1[0], arg2[0], arg3[0]);
1136 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1139 uint8_t *arg1 = ctx->code_position;
1140 uint8_t *arg2 = arg1 + arg_size(*arg1);
1141 ctx->code_position = arg2 + arg_size(*arg2);
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;
1152 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1156 internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, arg1[0], arg2[0]);
1160 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx)
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));
1174 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
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));
1187 switch (fp_op_size) {
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));
1208 internal(file_line, "cgen_fp_from_int: invalid arguments %u, %02x, %02x", fp_op_size, arg1[0], arg2[0]);
1212 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
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;
1223 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
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));
1231 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
1235 unsigned reg = cget_one(ctx);
1236 if (unlikely(!reg_is_p(reg)))
1247 if (likely(length == JMP_SHORTEST)) {
1248 mc = IA64_B_BR21 | IA64_BR_DPNT;
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;
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;
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));
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)
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));
1283 static uint64_t extract_bundle(uint8_t *ptr, unsigned bundle)
1286 memcpy(mc, ptr, 16);
1288 case 0: return mc[0] >> 5 & 0x1ffffffffffULL;
1290 case 1: return mc[0] >> 46 | (mc[1] & 0x7fffffULL) << 18;
1292 case 2: return mc[1] >> 23;
1294 default:internal(file_line, "extract_bundle: invalid bundle %u", bundle);
1298 static void insert_bundle(uint8_t *ptr, unsigned bundle, uint64_t instr)
1301 memcpy(mc, ptr, 16);
1303 case 0: mc[0] = (mc[0] & ~(0x1ffffffffffULL << 5)) | instr << 5;
1305 case 1: mc[0] = (mc[0] & ~(-1ULL << 46)) | instr << 46;
1306 mc[1] = (mc[1] & ~0x7fffffULL) | instr >> 18;
1308 case 2: mc[1] = (mc[1] & ~(-1ULL << 23)) | instr << 23;
1310 default:internal(file_line, "insert_bundle: invalid bundle %u", bundle);
1312 memcpy(ptr, mc, 16);
1315 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
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) {
1325 if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
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);
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);
1345 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1350 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1353 switch (insn_opcode(insn)) {
1355 full = ia64_fill_bundle(ctx);
1357 ctx->mcode_size += 16;
1360 ctx->mcode_size -= 16;
1363 full = ia64_fill_bundle(ctx);
1365 ctx->mcode_size += 16;
1368 ctx->mcode_size -= 16;
1371 g(cgen_ia64_ret(ctx));
1372 g(ia64_purge_bundle(ctx));
1374 case INSN_IA64_ALLOC:
1375 g(cgen_ia64_alloc(ctx));
1377 case INSN_IA64_DEALLOC:
1378 g(cgen_ia64_dealloc(ctx));
1380 case INSN_CALL_INDIRECT:
1381 g(cgen_call_indirect(ctx));
1384 g(cgen_mov(ctx, insn_op_size(insn)));
1387 g(cgen_movsx(ctx, insn_op_size(insn)));
1389 case INSN_CMP_DEST_REG:
1390 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1392 g(cgen_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
1394 case INSN_TEST_DEST_REG:
1395 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1397 g(cgen_test_dest_reg(ctx, insn_aux(insn) & 63, insn_aux(insn) >> 6));
1400 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1402 g(cgen_alu(ctx, insn_aux(insn)));
1405 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1407 g(cgen_alu1(ctx, insn_aux(insn)));
1410 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1412 g(cgen_rot(ctx, insn_aux(insn)));
1415 g(cgen_btx(ctx, insn_aux(insn)));
1418 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1420 g(cgen_movr(ctx, insn_aux(insn)));
1422 case INSN_FP_CMP_DEST_REG:
1423 g(cgen_fp_cmp_dest_reg(ctx, insn_aux(insn)));
1426 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1429 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1431 case INSN_FP_TO_INT64:
1432 g(cgen_fp_to_int(ctx));
1434 case INSN_FP_FROM_INT64:
1435 g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1438 g(cgen_jmp(ctx, insn_jump_size(insn)));
1441 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1443 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1445 case INSN_JMP_INDIRECT:
1446 g(cgen_jmp_indirect(ctx));
1450 internal(file_line, "cgen_insn: invalid insn %08x", insn);