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 return mask[bit >> 6] & 1ULL << (bit & 63);
197 static void set_mask(uint64_t mask[4], uint8_t bit)
199 if (bit == ACCESS_NOTHING)
201 mask[bit >> 6] |= 1ULL << (bit & 63);
204 static uint32_t get_possible_templates(struct codegen_context *ctx)
208 for (i = 0; i < 32; i++) {
209 uint32_t tmpl = templates[i];
210 for (j = 0; j < 3; j++) {
211 uint8_t insn_unit = ctx->a.insn_units[j];
212 uint8_t tmpl_unit = tmpl >> (j * 8) & 0xff;
213 if (!(tmpl_unit & insn_unit)) {
216 if (ctx->a.insn_stops[j] != (tmpl >> (24 + j) & 1)) {
226 static uint64_t get_nop(unsigned unit)
229 case UNIT_I: return IA64_I_NOP;
230 case UNIT_M: return IA64_M_NOP;
231 case UNIT_B: return IA64_B_NOP;
232 case UNIT_F: return IA64_F_NOP;
233 case UNIT_L: return IA64_L_NOP;
234 case UNIT_X: return IA64_X_NOP;
235 default: internal(file_line, "get_nop: invalid unit %x", unit);
240 static unsigned get_free_slot(struct codegen_context *ctx)
243 while (slot > 0 && ctx->a.insns[slot - 1] == -1ULL)
248 static bool attr_w ia64_purge_bundle(struct codegen_context *ctx)
253 if (!get_free_slot(ctx))
255 tmpls = get_possible_templates(ctx);
256 if (unlikely(!tmpls))
257 internal(file_line, "ia64_purge_bundle: no possible templates");
258 tmpl = low_bit(tmpls);
259 for (i = 0; i < 3; i++) {
260 if (ctx->a.insns[i] == -1ULL) {
261 ctx->a.insns[i] = get_nop(templates[tmpl] >> (i * 8) & 0xff);
262 ctx->a.insn_units[i] = templates[tmpl] >> (i * 8) & 0xff;
265 low = tmpl | ctx->a.insns[0] << 5 | ctx->a.insns[1] << 46;
266 high = ctx->a.insns[1] >> 18 | ctx->a.insns[2] << 23;
273 static bool ia64_fill_bundle(struct codegen_context *ctx)
277 if (!get_free_slot(ctx))
279 tmpls = get_possible_templates(ctx);
280 if (unlikely(!tmpls))
281 internal(file_line, "ia64_fill_bundle: no possible templates");
282 tmpl = low_bit(tmpls);
283 for (i = 0; i < 3; i++) {
284 if (ctx->a.insns[i] == -1ULL) {
285 ctx->a.insns[i] = get_nop(templates[tmpl] >> (i * 8) & 0xff);
286 ctx->a.insn_units[i] = templates[tmpl] >> (i * 8) & 0xff;
292 static bool attr_w ia64_insn(struct codegen_context *ctx, uint8_t unit, uint64_t mc, uint8_t wr1, uint8_t wr2, uint8_t rd1, uint8_t rd2, uint8_t rd3)
294 unsigned slot = get_free_slot(ctx);
295 bool need_stop = false;
296 need_stop |= test_mask(ctx->a.wr_mask, wr1);
297 need_stop |= test_mask(ctx->a.wr_mask, wr2);
298 need_stop |= test_mask(ctx->a.wr_mask, rd1);
299 need_stop |= test_mask(ctx->a.wr_mask, rd2);
300 need_stop |= test_mask(ctx->a.wr_mask, rd3);
301 /*debug("ia64_insn: %x, %lx, %d, %u", unit, mc, need_stop, slot);*/
304 try_stop_in_next_slot:
305 ctx->a.insn_stops[slot - 1] = need_stop;
306 if (!get_possible_templates(ctx)) {
307 ctx->a.insn_stops[slot - 1] = false;
309 if (unlikely(slot > 3))
310 internal(file_line, "ia64_insn: can't set stop at the end of the bundle");
311 goto try_stop_in_next_slot;
315 g(ia64_purge_bundle(ctx));
323 ctx->a.insn_units[slot] = unit;
324 if (!get_possible_templates(ctx)) {
325 ctx->a.insn_units[slot] = 0xff;
327 if (unlikely(slot == 3)) {
328 g(ia64_purge_bundle(ctx));
333 ctx->a.insns[slot] = mc;
334 set_mask(ctx->a.wr_mask, wr1);
335 set_mask(ctx->a.wr_mask, wr2);
339 static bool attr_w cgen_ia64_ret(struct codegen_context *ctx)
343 mc |= bits_b(B_0) << 13;
344 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_MEMORY, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
346 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_MEMORY, ACCESS_NOTHING, ACCESS_NOTHING));
350 static bool attr_w cgen_ia64_alloc(struct codegen_context *ctx)
353 uint8_t *arg1 = ctx->code_position;
354 uint8_t *arg2 = arg1 + arg_size(*arg1);
355 uint8_t *arg3 = arg2 + arg_size(*arg2);
356 ctx->code_position = arg3 + arg_size(*arg3);
357 ia64_fill_bundle(ctx);
359 mc |= bits_gr(arg1[0]) << 6;
360 mc |= get_imm(&arg2[1]) << 13;
361 mc |= get_imm(&arg3[1]) << 20;
362 g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
366 static bool attr_w cgen_ia64_dealloc(struct codegen_context *ctx)
369 uint8_t *arg1 = ctx->code_position;
370 ctx->code_position = arg1 + arg_size(*arg1);
371 mc = IA64_I_MOV_TO_AR | IA64_I_MOV_TO_AR_PFS;
372 mc |= bits_gr(arg1[0]) << 13;
373 g(ia64_insn(ctx, UNIT_I, mc, ACCESS_NOTHING, ACCESS_NOTHING, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING));
377 static bool attr_w cgen_call_indirect(struct codegen_context *ctx)
380 unsigned reg = cget_one(ctx);
381 mc = IA64_B_BR_CALL_INDIRECT;
382 mc |= bits_b(B_0) << 6;
383 mc |= bits_b(reg) << 13;
384 g(ia64_insn(ctx, UNIT_B, mc, B_0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
388 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
393 uint8_t *arg1 = ctx->code_position;
394 uint8_t *arg2 = arg1 + arg_size(*arg1);
395 ctx->code_position = arg2 + arg_size(*arg2);
397 if (reg_is_gr(arg1[0])) {
398 if (reg_is_gr(arg2[0])) {
410 mc = IA64_A_ADD_IMM14;
411 mc |= bits_gr(arg1[0]) << 6;
412 mc |= bits_gr(arg2[0]) << 20;
413 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
418 mc |= bits_gr(arg1[0]) << 6;
419 mc |= bits_gr(arg2[0]) << 20;
420 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
423 if (reg_is_fp(arg2[0])) {
424 mc = IA64_M_GETF_SIG;
425 mc |= bits_gr(arg1[0]) << 6;
426 mc |= bits_fp(arg2[0]) << 13;
427 g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
430 if (reg_is_b(arg2[0])) {
431 mc = IA64_I_MOVE_FROM_BR;
432 mc |= bits_gr(arg1[0]) << 6;
433 mc |= bits_b(arg2[0]) << 13;
434 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
437 if (reg_is_p(arg2[0])) {
438 mc = IA64_A_ADD_IMM14;
439 mc |= bits_gr(arg1[0]) << 6;
440 mc |= (uint64_t)1 << 13;
441 mc |= bits_p(arg2[0]);
442 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
444 mc = IA64_A_ADD_IMM14;
445 mc |= bits_gr(arg1[0]) << 6;
446 mc |= bits_p(arg2[0] ^ 1);
447 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
451 if (arg2[0] == ARG_ADDRESS_1) {
452 imm = get_imm(&arg2[2]);
453 if (unlikely(imm != 0))
456 case OP_SIZE_1: mc = IA64_M_LD1; break;
457 case OP_SIZE_2: mc = IA64_M_LD2; break;
458 case OP_SIZE_4: mc = IA64_M_LD4; break;
459 case OP_SIZE_8: mc = IA64_M_LD8; break;
460 default: goto invalid;
462 mc |= bits_gr(arg1[0]) << 6;
463 mc |= bits_gr(arg2[1]) << 20;
464 g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_MEMORY, ACCESS_NOTHING));
467 if (arg2[0] == ARG_IMM) {
468 imm = get_imm(&arg2[1]);
469 if (imm >= -0x200000 && imm < 0x200000) {
470 mc = IA64_A_ADD_IMM22;
471 mc |= bits_gr(arg1[0]) << 6;
472 mc |= (imm & 0x7f) << 13;
473 mc |= ((uint64_t)imm >> 7 & 0x1ff) << 27;
474 mc |= ((uint64_t)imm >> 16 & 0x1f) << 22;
475 mc |= ((uint64_t)imm >> 21 & 0x1) << 36;
476 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
479 mc = (imm & 0x7fffffffffc00000ULL) >> 22;
480 g(ia64_insn(ctx, UNIT_L, mc, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
482 mc |= bits_gr(arg1[0]) << 6;
483 mc |= (imm & 0x7f) << 13;
484 mc |= ((uint64_t)imm >> 7 & 0x1ff) << 27;
485 mc |= ((uint64_t)imm >> 16 & 0x1f) << 22;
486 mc |= ((uint64_t)imm >> 21 & 0x1) << 21;
487 mc |= ((uint64_t)imm >> 63) << 36;
488 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
493 if (reg_is_fp(arg1[0])) {
494 if (reg_is_gr(arg2[0])) {
495 mc = IA64_M_SETF_SIG;
496 mc |= bits_fp(arg1[0]) << 6;
497 mc |= bits_gr(arg2[0]) << 13;
498 g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_NOTHING, ACCESS_NOTHING));
501 if (arg2[0] == ARG_ADDRESS_1) {
502 imm = get_imm(&arg2[2]);
503 if (unlikely(imm != 0))
506 case OP_SIZE_4: mc = IA64_M_LDFS; break;
507 case OP_SIZE_8: mc = IA64_M_LDFD; break;
508 case OP_SIZE_10:mc = IA64_M_LDFE; break;
509 default: goto invalid;
511 mc |= bits_fp(arg1[0]) << 6;
512 mc |= bits_gr(arg2[1]) << 20;
513 g(ia64_insn(ctx, UNIT_M, mc, arg1[0], ACCESS_NOTHING, arg2[1], ACCESS_MEMORY, ACCESS_NOTHING));
517 if (reg_is_b(arg1[0])) {
518 if (reg_is_gr(arg2[0])) {
519 mc = IA64_I_MOVE_TO_BR;
520 mc |= bits_gr(arg2[0]) << 13;
521 mc |= bits_b(arg1[0]) << 6;
522 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
526 if (arg1[0] == ARG_ADDRESS_1) {
527 imm = get_imm(&arg1[2]);
528 if (unlikely(imm != 0))
530 if (arg2[0] == ARG_IMM) {
531 imm = get_imm(&arg2[1]);
532 if (unlikely(imm != 0))
536 if (reg_is_gr(arg2[0])) {
538 case OP_SIZE_1: mc = IA64_M_ST1; break;
539 case OP_SIZE_2: mc = IA64_M_ST2; break;
540 case OP_SIZE_4: mc = IA64_M_ST4; break;
541 case OP_SIZE_8: mc = IA64_M_ST8; break;
542 default: goto invalid;
544 mc |= bits_gr(arg2[0]) << 13;
545 mc |= bits_gr(arg1[1]) << 20;
546 g(ia64_insn(ctx, UNIT_M, mc, ACCESS_MEMORY, ACCESS_NOTHING, arg1[1], arg2[0], ACCESS_NOTHING));
549 if (reg_is_fp(arg2[0])) {
551 case OP_SIZE_4: mc = IA64_M_STFS; break;
552 case OP_SIZE_8: mc = IA64_M_STFD; break;
553 case OP_SIZE_10:mc = IA64_M_STFE; break;
554 default: goto invalid;
556 mc |= bits_fp(arg2[0]) << 13;
557 mc |= bits_gr(arg1[1]) << 20;
558 g(ia64_insn(ctx, UNIT_M, mc, ACCESS_MEMORY, ACCESS_NOTHING, arg1[1], arg2[0], ACCESS_NOTHING));
564 internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u", arg1[0], arg2[0], size);
568 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
571 uint8_t *arg1 = ctx->code_position;
572 uint8_t *arg2 = arg1 + arg_size(*arg1);
573 ctx->code_position = arg2 + arg_size(*arg2);
575 if (likely(reg_is_gr(arg1[0])) && likely(reg_is_gr(arg2[0]))) {
587 mc = IA64_A_ADD_IMM14;
588 mc |= bits_gr(arg1[0]) << 6;
589 mc |= bits_gr(arg2[0]) << 20;
590 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
595 mc |= bits_gr(arg1[0]) << 6;
596 mc |= bits_gr(arg2[0]) << 20;
597 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
602 internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u", arg1[0], arg2[0], size);
606 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned cond)
610 bool swap_preds = false, swap_regs = false;
612 uint8_t *arg1 = ctx->code_position;
613 uint8_t *arg2 = arg1 + arg_size(*arg1);
614 uint8_t *arg3 = arg2 + arg_size(*arg2);
615 ctx->code_position = arg3 + arg_size(*arg3);
617 if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
622 if (arg3[0] == ARG_IMM) {
623 int64_t imm = get_imm(&arg3[1]);
628 if (unlikely(imm <= -0x80) || unlikely(imm >= 0x80))
631 case COND_AE: mc = IA64_A_CMP_LTU_IMM8; imm--; break;
632 case COND_B: mc = IA64_A_CMP_LTU_IMM8; imm--; swap_preds = true; break;
633 case COND_E: mc = IA64_A_CMP_EQ_IMM8; break;
634 case COND_NE: mc = IA64_A_CMP_EQ_IMM8; swap_preds = true; break;
635 case COND_BE: mc = IA64_A_CMP_LTU_IMM8; swap_preds = true; break;
636 case COND_A: mc = IA64_A_CMP_LTU_IMM8; break;
637 case COND_L: mc = IA64_A_CMP_LT_IMM8; imm--; swap_preds = true; break;
638 case COND_GE: mc = IA64_A_CMP_LT_IMM8; imm--; break;
639 case COND_LE: mc = IA64_A_CMP_LT_IMM8; swap_preds = true; break;
640 case COND_G: mc = IA64_A_CMP_LT_IMM8; break;
641 default: goto invalid;
647 if (op_size == OP_SIZE_4)
650 mc |= (imm & 0x7f) << 13;
651 mc |= ((uint64_t)imm >> 7 & 1) << 36;
652 mc |= bits_gr(arg2[0]) << 20;
653 mc |= bits_p(pred) << 6;
654 mc |= bits_p(pred ^ 1) << 27;
655 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], arg3[0], ACCESS_NOTHING));
659 if (!reg_is_gr(arg3[0]))
664 case COND_B: mc = IA64_A_CMP_LTU; break;
665 case COND_AE: mc = IA64_A_CMP_LTU; swap_preds = true; break;
666 case COND_E: mc = IA64_A_CMP_EQ; break;
667 case COND_NE: mc = IA64_A_CMP_EQ; swap_preds = true; break;
668 case COND_BE: mc = IA64_A_CMP_LTU; swap_regs = true; swap_preds = true; break;
669 case COND_A: mc = IA64_A_CMP_LTU; swap_regs = true; break;
670 case COND_L: mc = IA64_A_CMP_LT; break;
671 case COND_GE: mc = IA64_A_CMP_LT; swap_preds = true; break;
672 case COND_LE: mc = IA64_A_CMP_LT; swap_regs = true; swap_preds = true; break;
673 case COND_G: mc = IA64_A_CMP_LT; swap_regs = true; break;
674 default: goto invalid;
678 uint8_t *argx = arg2;
686 if (op_size == OP_SIZE_4)
689 mc |= bits_gr(arg2[0]) << 13;
690 mc |= bits_gr(arg3[0]) << 20;
691 mc |= bits_p(pred) << 6;
692 mc |= bits_p(pred ^ 1) << 27;
693 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], arg1[0] ^ 1, arg2[0], arg3[0], ACCESS_NOTHING));
697 internal(file_line, "cgen_cmp_dest_reg: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
701 static bool attr_w cgen_test_dest_reg(struct codegen_context *ctx, unsigned bit, bool jnz)
705 uint8_t *arg1 = ctx->code_position;
706 uint8_t *arg2 = arg1 + arg_size(*arg1);
707 ctx->code_position = arg2 + arg_size(*arg2);
709 if (unlikely(!reg_is_p(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
718 mc |= (uint64_t)bit << 14;
719 mc |= bits_gr(arg2[0]) << 20;
720 mc |= bits_p(pred) << 6;
721 mc |= bits_p(pred ^ 1) << 27;
722 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], arg1[0] ^ 1, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
726 internal(file_line, "cgen_test_dest_reg: invalid arguments %02x, %02x", arg1[0], arg2[0]);
730 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned alu)
733 uint8_t *arg1 = ctx->code_position;
734 uint8_t *arg2 = arg1 + arg_size(*arg1);
735 uint8_t *arg3 = arg2 + arg_size(*arg2);
736 ctx->code_position = arg3 + arg_size(*arg3);
738 if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
739 uint8_t *arg_swp = arg3;
744 if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
748 if (reg_is_gr(arg3[0])) {
751 case ALU_ADD: mc |= IA64_A_ALU_ADD; break;
752 case ALU_SUB: mc |= IA64_A_ALU_SUB; break;
753 case ALU_AND: mc |= IA64_A_ALU_AND; break;
754 case ALU_ANDN: mc |= IA64_A_ALU_ANDCM; break;
755 case ALU_OR: mc |= IA64_A_ALU_OR; break;
756 case ALU_XOR: mc |= IA64_A_ALU_XOR; break;
757 default: goto invalid;
759 mc |= bits_gr(arg1[0]) << 6;
760 mc |= bits_gr(arg2[0]) << 13;
761 mc |= bits_gr(arg3[0]) << 20;
762 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
766 if (arg3[0] == ARG_SHIFTED_REGISTER && (arg3[1] & ARG_SHIFT_MODE) == ARG_SHIFT_LSL) {
767 unsigned amount = arg3[1] & ARG_SHIFT_AMOUNT;
772 if (unlikely(amount > 4))
775 mc |= bits_gr(arg1[0]) << 6;
776 mc |= bits_gr(arg3[2]) << 13;
777 mc |= bits_gr(arg2[0]) << 20;
778 mc |= (amount - 1) << 27;
779 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[2], ACCESS_NOTHING));
783 if (arg3[0] == ARG_IMM) {
784 int64_t imm = get_imm(&arg3[1]);
785 if (alu == ALU_SUB) {
786 imm = -(uint64_t)imm;
789 if (alu == ALU_ADD) {
790 if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
792 mc = IA64_A_ADD_IMM14;
793 mc |= bits_gr(arg1[0]) << 6;
794 mc |= bits_gr(arg2[0]) << 20;
795 mc |= (imm & 0x7f) << 13;
796 mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
797 mc |= ((uint64_t)imm >> 13 & 1) << 36;
798 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
800 } else if (alu == ALU_AND || alu == ALU_OR || alu == ALU_XOR) {
801 if (unlikely(imm < -0x80) || unlikely(imm >= 0x80))
803 mc = IA64_A_ALU_IMM8 | (alu == ALU_AND ? IA64_A_ALU_IMM8_AND : alu == ALU_OR ? IA64_A_ALU_IMM8_OR : IA64_A_ALU_IMM8_XOR);
804 mc |= bits_gr(arg1[0]) << 6;
805 mc |= bits_gr(arg2[0]) << 20;
806 mc |= (imm & 0x7f) << 13;
807 mc |= ((uint64_t)imm >> 7 & 1) << 36;
808 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
816 internal(file_line, "cgen_alu: invalid arguments %u, %02x, %02x, %02x", alu, arg1[0], arg2[0], arg3[0]);
820 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned alu)
823 uint8_t *arg1 = ctx->code_position;
824 uint8_t *arg2 = arg1 + arg_size(*arg1);
825 ctx->code_position = arg2 + arg_size(*arg2);
827 if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
832 case ALU1_NOT: mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_ANDCM;
833 mc |= bits_gr(arg1[0]) << 6;
834 mc |= bits_gr(arg2[0]) << 20;
837 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
839 case ALU1_NEG: mc = IA64_A_ALU_IMM8 | IA64_A_ALU_IMM8_SUB;
840 mc |= bits_gr(arg1[0]) << 6;
841 mc |= bits_gr(arg2[0]) << 20;
842 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
844 case ALU1_INC: mc = IA64_A_ADD_IMM14;
845 mc |= bits_gr(arg1[0]) << 6;
846 mc |= bits_gr(arg2[0]) << 20;
848 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
850 case ALU1_DEC: mc = IA64_A_ADD_IMM14;
851 mc |= bits_gr(arg1[0]) << 6;
852 mc |= bits_gr(arg2[0]) << 20;
856 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
858 case ALU1_BSWAP:mc = IA64_I_MUX1_REV;
859 mc |= bits_gr(arg1[0]) << 6;
860 mc |= bits_gr(arg1[1]) << 13;
861 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
865 mc |= bits_gr(arg1[0]) << 6;
866 mc |= bits_gr(arg2[0]) << 20;
867 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
869 default: goto invalid;
873 internal(file_line, "cgen_alu1: invalid arguments %u, %02x, %02x", alu, arg1[0], arg2[0]);
878 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned rot)
881 uint8_t *arg1 = ctx->code_position;
882 uint8_t *arg2 = arg1 + arg_size(*arg1);
883 uint8_t *arg3 = arg2 + arg_size(*arg2);
884 ctx->code_position = arg3 + arg_size(*arg3);
886 if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])))
889 if (arg3[0] == ARG_IMM) {
890 uint64_t pos = get_imm(&arg3[1]) & 63;
891 uint64_t len = 64 - pos - 1;
893 case ROT_SHL: mc = IA64_I_DEP_Z;
894 mc |= bits_gr(arg1[0]) << 6;
895 mc |= bits_gr(arg2[0]) << 13;
896 mc |= (pos ^ 0x3f) << 20;
899 case ROT_SHR: mc = IA64_I_EXTR_U;
900 mc |= bits_gr(arg1[0]) << 6;
902 mc |= bits_gr(arg2[0]) << 20;
905 case ROT_SAR: mc = IA64_I_EXTR;
906 mc |= bits_gr(arg1[0]) << 6;
908 mc |= bits_gr(arg2[0]) << 20;
911 default: goto invalid;
913 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
917 if (reg_is_gr(arg3[0])) {
919 case ROT_SHL: mc = IA64_I_SHL;
920 mc |= bits_gr(arg1[0]) << 6;
921 mc |= bits_gr(arg2[0]) << 13;
922 mc |= bits_gr(arg3[0]) << 20;
924 case ROT_SHR: mc = IA64_I_SHR_U;
925 mc |= bits_gr(arg1[0]) << 6;
926 mc |= bits_gr(arg3[0]) << 13;
927 mc |= bits_gr(arg2[0]) << 20;
929 case ROT_SAR: mc = IA64_I_SHR;
930 mc |= bits_gr(arg1[0]) << 6;
931 mc |= bits_gr(arg3[0]) << 13;
932 mc |= bits_gr(arg2[0]) << 20;
934 default: goto invalid;
936 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
941 internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], rot);
945 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
949 uint8_t *arg1 = ctx->code_position;
950 uint8_t *arg2 = arg1 + arg_size(*arg1);
951 uint8_t *arg3 = arg2 + arg_size(*arg2);
952 ctx->code_position = arg3 + arg_size(*arg3);
953 if (unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_gr(arg2[0])) || unlikely(arg3[0] != ARG_IMM))
956 imm = get_imm(&arg3[1]) & 0x3f;
961 case BTX_BTS: mc |= 1ULL << 36;
964 default: goto invalid;
967 mc |= bits_gr(arg1[0]) << 6;
968 mc |= bits_gr(arg2[0]) << 20;
970 mc |= (imm ^ 0x3f) << 14;
972 g(ia64_insn(ctx, UNIT_I, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
976 internal(file_line, "cgen_rot: invalid arguments %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
980 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
984 uint8_t *arg1 = ctx->code_position;
985 uint8_t *arg2 = arg1 + arg_size(*arg1);
986 uint8_t *arg3 = arg2 + arg_size(*arg2);
987 uint8_t *arg4 = arg3 + arg_size(*arg3);
988 ctx->code_position = arg4 + arg_size(*arg4);
989 if (unlikely(arg1[0] != arg2[0]) || unlikely(!reg_is_gr(arg1[0])) || unlikely(!reg_is_p(arg3[0])))
994 case COND_E: pred ^= 1; break;
996 default: goto invalid;
999 if (arg4[0] == ARG_IMM) {
1000 int64_t imm = get_imm(&arg4[1]);
1001 if (unlikely(imm < -0x2000) || unlikely(imm >= 0x2000))
1003 mc = IA64_A_ADD_IMM14;
1004 mc |= bits_gr(arg1[0]) << 6;
1005 mc |= (imm & 0x7f) << 13;
1006 mc |= ((uint64_t)imm >> 7 & 0x3f) << 27;
1007 mc |= ((uint64_t)imm >> 13 & 1) << 36;
1009 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1013 if (reg_is_gr(arg4[0])) {
1014 mc = IA64_A_ADD_IMM14;
1015 mc |= bits_gr(arg1[0]) << 6;
1016 mc |= bits_gr(arg4[0]) << 20;
1018 g(ia64_insn(ctx, UNIT_A, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], arg4[0]));
1023 internal(file_line, "cgen_movr: invalid arguments %02x, %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], arg4[0], aux);
1027 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
1031 bool swap_preds = false, swap_regs = false;
1032 uint8_t *arg1 = ctx->code_position;
1033 uint8_t *arg2 = arg1 + arg_size(*arg1);
1034 uint8_t *arg3 = arg2 + arg_size(*arg2);
1035 ctx->code_position = arg3 + arg_size(*arg3);
1040 case FP_COND_P: mc |= IA64_F_FCMP_UNORD; break;
1041 case FP_COND_NP:mc |= IA64_F_FCMP_UNORD; swap_preds = true; break;
1042 case FP_COND_E: mc |= IA64_F_FCMP_EQ; break;
1043 case FP_COND_NE:mc |= IA64_F_FCMP_EQ; swap_preds = true; break;
1044 case FP_COND_A: mc |= IA64_F_FCMP_LT; swap_regs = true; break;
1045 case FP_COND_BE:mc |= IA64_F_FCMP_LE; break;
1046 case FP_COND_B: mc |= IA64_F_FCMP_LT; break;
1047 case FP_COND_AE:mc |= IA64_F_FCMP_LE; swap_regs = true; break;
1051 uint8_t *argx = arg2;
1059 mc |= bits_fp(arg2[0]) << 13;
1060 mc |= bits_fp(arg3[0]) << 20;
1061 mc |= bits_p(pred) << 6;
1062 mc |= bits_p(pred ^ 1) << 27;
1063 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1067 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1069 uint64_t mc, f1, f2, f3, f4;
1070 uint8_t *arg1 = ctx->code_position;
1071 uint8_t *arg2 = arg1 + arg_size(*arg1);
1072 uint8_t *arg3 = arg2 + arg_size(*arg2);
1073 ctx->code_position = arg3 + arg_size(*arg3);
1077 f1 = bits_fp(arg1[0]);
1078 f2 = bits_fp(arg3[0]);
1079 f3 = bits_fp(arg2[0]);
1080 f4 = bits_fp(FR_ONE);
1084 f1 = bits_fp(arg1[0]);
1085 f2 = bits_fp(arg3[0]);
1086 f3 = bits_fp(arg2[0]);
1087 f4 = bits_fp(FR_ONE);
1091 f1 = bits_fp(arg1[0]);
1092 f2 = bits_fp(FR_ZERO);
1093 f3 = bits_fp(arg2[0]);
1094 f4 = bits_fp(arg3[0]);
1116 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], arg3[0], ACCESS_NOTHING));
1120 internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, arg1[0], arg2[0], arg3[0]);
1124 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
1127 uint8_t *arg1 = ctx->code_position;
1128 uint8_t *arg2 = arg1 + arg_size(*arg1);
1129 ctx->code_position = arg2 + arg_size(*arg2);
1132 mc = IA64_F_FMERGE_NS;
1133 mc |= bits_fp(arg1[0]) << 6;
1134 mc |= bits_fp(arg2[0]) << 13;
1135 mc |= bits_fp(arg2[0]) << 20;
1140 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1144 internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, arg1[0], arg2[0]);
1148 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx)
1151 uint8_t *arg1 = ctx->code_position;
1152 uint8_t *arg2 = arg1 + arg_size(*arg1);
1153 ctx->code_position = arg2 + arg_size(*arg2);
1155 mc = IA64_F_FCVT_FX_TRUNC;
1156 mc |= bits_fp(arg1[0]) << 6;
1157 mc |= bits_fp(arg2[0]) << 13;
1158 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1162 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
1165 uint8_t *arg1 = ctx->code_position;
1166 uint8_t *arg2 = arg1 + arg_size(*arg1);
1167 ctx->code_position = arg2 + arg_size(*arg2);
1169 mc = IA64_F_FCVT_XF;
1170 mc |= bits_fp(arg1[0]) << 6;
1171 mc |= bits_fp(arg2[0]) << 13;
1172 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg2[0], ACCESS_NOTHING, ACCESS_NOTHING));
1175 switch (fp_op_size) {
1187 mc |= bits_fp(arg1[0]) << 6;
1188 mc |= bits_fp(FR_ZERO) << 13;
1189 mc |= bits_fp(arg1[0]) << 20;
1190 mc |= bits_fp(FR_ONE) << 27;
1191 g(ia64_insn(ctx, UNIT_F, mc, arg1[0], ACCESS_NOTHING, arg1[0], ACCESS_NOTHING, ACCESS_NOTHING));
1196 internal(file_line, "cgen_fp_from_int: invalid arguments %u, %02x, %02x", fp_op_size, arg1[0], arg2[0]);
1200 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
1204 if (length == JMP_SHORTEST) {
1205 g(ia64_insn(ctx, UNIT_B, IA64_B_BR21, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1206 bundle = get_free_slot(ctx) - 1;
1207 ctx->mcode_size += bundle;
1208 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1209 ctx->mcode_size -= bundle;
1211 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1213 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1214 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1219 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
1223 unsigned reg = cget_one(ctx);
1224 if (unlikely(!reg_is_p(reg)))
1235 if (likely(length == JMP_SHORTEST)) {
1236 mc = IA64_B_BR21 | IA64_BR_DPNT;
1238 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1239 bundle = get_free_slot(ctx) - 1;
1240 ctx->mcode_size += bundle;
1241 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
1242 ctx->mcode_size -= bundle;
1244 g(ia64_insn(ctx, UNIT_L, 0, ACCESS_NOTHING, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1245 mc = IA64_X_BRL | IA64_BR_DPNT;
1247 g(ia64_insn(ctx, UNIT_X, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1248 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
1252 internal(file_line, "cgen_jmp_reg: invalid arguments %x, %x, %x", reg, aux, length);
1255 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
1258 unsigned reg = cget_one(ctx);
1260 mc = IA64_I_MOVE_TO_BR;
1261 mc |= bits_gr(reg) << 13;
1262 mc |= bits_b(R_SCRATCH_B) << 6;
1263 g(ia64_insn(ctx, UNIT_I, mc, R_SCRATCH_B, ACCESS_NOTHING, reg, ACCESS_NOTHING, ACCESS_NOTHING));
1265 mc = IA64_B_BR_JMP_INDIRECT;
1266 mc |= bits_b(R_SCRATCH_B) << 13;
1267 g(ia64_insn(ctx, UNIT_B, mc, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING, ACCESS_NOTHING));
1271 static uint64_t extract_bundle(uint8_t *ptr, unsigned bundle)
1274 memcpy(mc, ptr, 16);
1276 case 0: return mc[0] >> 5 & 0x1ffffffffffULL;
1278 case 1: return mc[0] >> 46 | (mc[1] & 0x7fffffULL) << 18;
1280 case 2: return mc[1] >> 23;
1282 default:internal(file_line, "extract_bundle: invalid bundle %u", bundle);
1286 static void insert_bundle(uint8_t *ptr, unsigned bundle, uint64_t instr)
1289 memcpy(mc, ptr, 16);
1291 case 0: mc[0] = (mc[0] & ~(0x1ffffffffffULL << 5)) | instr << 5;
1293 case 1: mc[0] = (mc[0] & ~(-1ULL << 46)) | instr << 46;
1294 mc[1] = (mc[1] & ~0x7fffffULL) | instr >> 18;
1296 case 2: mc[1] = (mc[1] & ~(-1ULL << 23)) | instr << 23;
1298 default:internal(file_line, "insert_bundle: invalid bundle %u", bundle);
1300 memcpy(ptr, mc, 16);
1303 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1307 unsigned bundle = reloc->position & 3;
1308 size_t position = reloc->position & ~3;
1309 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 4) - (int64_t)(position >> 4);
1310 /*debug("relocation: position %lx, bundle %x, offset %lx, label %lx", reloc->position, bundle, offs, ctx->label_to_pos[reloc->label_id]);*/
1311 switch (reloc->length) {
1313 if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
1315 mc = extract_bundle(ctx->mcode + position, bundle);
1316 mc &= ~0x011ffffe000ULL;
1317 mc |= (offs & 0xfffffULL) << 13;
1318 mc |= ((uint64_t)offs >> 20 & 1) << 36;
1319 insert_bundle(ctx->mcode + position, bundle, mc);
1322 imm41 = extract_bundle(ctx->mcode + position, 1);
1323 mc = extract_bundle(ctx->mcode + position, 2);
1324 mc &= ~0x011ffffe000ULL;
1325 mc |= (offs & 0xfffffULL) << 13;
1326 imm41 &= ~0x1fffffffffcULL;
1327 imm41 |= (offs >> 20 << 2) & 0x1fffffffffcULL;
1328 mc |= ((uint64_t)offs >> 59 & 1) << 36;
1329 insert_bundle(ctx->mcode + position, 1, imm41);
1330 insert_bundle(ctx->mcode + position, 2, mc);
1333 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1338 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1341 switch (insn_opcode(insn)) {
1343 full = ia64_fill_bundle(ctx);
1345 ctx->mcode_size += 16;
1348 ctx->mcode_size -= 16;
1351 full = ia64_fill_bundle(ctx);
1353 ctx->mcode_size += 16;
1356 ctx->mcode_size -= 16;
1359 g(cgen_ia64_ret(ctx));
1360 g(ia64_purge_bundle(ctx));
1362 case INSN_IA64_ALLOC:
1363 g(cgen_ia64_alloc(ctx));
1365 case INSN_IA64_DEALLOC:
1366 g(cgen_ia64_dealloc(ctx));
1368 case INSN_CALL_INDIRECT:
1369 g(cgen_call_indirect(ctx));
1372 g(cgen_mov(ctx, insn_op_size(insn)));
1375 g(cgen_movsx(ctx, insn_op_size(insn)));
1377 case INSN_CMP_DEST_REG:
1378 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1380 g(cgen_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
1382 case INSN_TEST_DEST_REG:
1383 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1385 g(cgen_test_dest_reg(ctx, insn_aux(insn) & 63, insn_aux(insn) >> 6));
1388 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1390 g(cgen_alu(ctx, insn_aux(insn)));
1393 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1395 g(cgen_alu1(ctx, insn_aux(insn)));
1398 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1400 g(cgen_rot(ctx, insn_aux(insn)));
1403 g(cgen_btx(ctx, insn_aux(insn)));
1406 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1408 g(cgen_movr(ctx, insn_aux(insn)));
1410 case INSN_FP_CMP_DEST_REG:
1411 g(cgen_fp_cmp_dest_reg(ctx, insn_aux(insn)));
1414 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1417 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1419 case INSN_FP_TO_INT64:
1420 g(cgen_fp_to_int(ctx));
1422 case INSN_FP_FROM_INT64:
1423 g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1426 g(cgen_jmp(ctx, insn_jump_size(insn)));
1429 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1431 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1433 case INSN_JMP_INDIRECT:
1434 g(cgen_jmp_indirect(ctx));
1438 internal(file_line, "cgen_insn: invalid insn %08x", insn);