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 ALPHA_OPERATE_LITERAL 0x00001000U
21 #define ALPHA_ADDL 0x40000000U
22 #define ALPHA_ADDL_V 0x40000800U
23 #define ALPHA_S4ADDL 0x40000040U
24 #define ALPHA_S8ADDL 0x40000240U
25 #define ALPHA_ADDQ 0x40000400U
26 #define ALPHA_ADDQ_V 0x40000c00U
27 #define ALPHA_S4ADDQ 0x40000440U
28 #define ALPHA_S8ADDQ 0x40000640U
29 #define ALPHA_SUBL 0x40000120U
30 #define ALPHA_SUBL_V 0x40000920U
31 #define ALPHA_S4SUBL 0x40000160U
32 #define ALPHA_S8SUBL 0x40000360U
33 #define ALPHA_SUBQ 0x40000520U
34 #define ALPHA_SUBQ_V 0x40000d20U
35 #define ALPHA_S4SUBQ 0x40000560U
36 #define ALPHA_S8SUBQ 0x40000760U
38 #define ALPHA_CMOVLBS 0x44000280U
39 #define ALPHA_CMOVLBC 0x440002c0U
40 #define ALPHA_CMOVEQ 0x44000480U
41 #define ALPHA_CMOVNE 0x440004c0U
42 #define ALPHA_CMOVLT 0x44000880U
43 #define ALPHA_CMOVGE 0x440008c0U
44 #define ALPHA_CMOVLE 0x44000c80U
45 #define ALPHA_CMOVGT 0x44000cc0U
47 #define ALPHA_LDA 0x20000000U
48 #define ALPHA_LDAH 0x24000000U
49 #define ALPHA_LDBU 0x28000000U
50 #define ALPHA_LDQ_U 0x2c000000U
51 #define ALPHA_LDWU 0x30000000U
52 #define ALPHA_STW 0x34000000U
53 #define ALPHA_STB 0x38000000U
54 #define ALPHA_STQ_U 0x3c000000U
56 #define ALPHA_CMPULT 0x400003a0U
57 #define ALPHA_CMPEQ 0x400005a0U
58 #define ALPHA_CMPULE 0x400007a0U
59 #define ALPHA_CMPLT 0x400009a0U
60 #define ALPHA_CMPLE 0x40000da0U
61 #define ALPHA_AND 0x44000000U
62 #define ALPHA_ANDNOT 0x44000100U
63 #define ALPHA_BIS 0x44000400U
64 #define ALPHA_ORNOT 0x44000500U
65 #define ALPHA_XOR 0x44000800U
66 #define ALPHA_EQV 0x44000900U
67 #define ALPHA_MSKBL 0x48000040U
68 #define ALPHA_EXTBL 0x480000c0U
69 #define ALPHA_INSBL 0x48000160U
70 #define ALPHA_EXTWL 0x480002c0U
71 #define ALPHA_EXTLL 0x480004c0U
72 #define ALPHA_ZAP 0x48000600U
73 #define ALPHA_ZAPNOT 0x48000620U
74 #define ALPHA_SRL 0x48000680U
75 #define ALPHA_SLL 0x48000720U
76 #define ALPHA_SRA 0x48000780U
77 #define ALPHA_EXTLH 0x48000d40U
78 #define ALPHA_MULL 0x4c000000U
79 #define ALPHA_MULQ 0x4c000400U
80 #define ALPHA_UMULH 0x4c000600U
81 #define ALPHA_MULL_V 0x4c000800U
82 #define ALPHA_MULQ_V 0x4c000c00U
84 #define ALPHA_ITOFS 0x501f0080U
85 #define ALPHA_ITOFT 0x501f0480U
86 #define ALPHA_SQRTS_SU 0x53e0b160U
87 #define ALPHA_SQRTT_SU 0x53e0b560U
89 #define ALPHA_CMPTEQ 0x580014a0U
90 #define ALPHA_CMPTLT 0x580014c0U
91 #define ALPHA_CMPTLE 0x580014e0U
92 #define ALPHA_CMPTUN_SU 0x5800b480U
93 #define ALPHA_ADDS_SU 0x5800b000U
94 #define ALPHA_SUBS_SU 0x5800b020U
95 #define ALPHA_MULS_SU 0x5800b040U
96 #define ALPHA_DIVS_SU 0x5800b060U
97 #define ALPHA_ADDT_SU 0x5800b400U
98 #define ALPHA_SUBT_SU 0x5800b420U
99 #define ALPHA_MULT_SU 0x5800b440U
100 #define ALPHA_DIVT_SU 0x5800b460U
101 #define ALPHA_CVTQS 0x5be01780U
102 #define ALPHA_CVTQT 0x5be017c0U
103 #define ALPHA_CVTTQ_V 0x5be035e0U
105 #define ALPHA_CPYS 0x5c000400U
106 #define ALPHA_CPYSN 0x5c000420U
107 #define ALPHA_CVTLQ 0x5fe00200U
108 #define ALPHA_CVTQL_V 0x5fe02600U
110 #define ALPHA_TRAPB 0x60000000U
111 #define ALPHA_MB 0x60004000U
112 #define ALPHA_JSR_T12 0x6b5b4000U
113 #define ALPHA_JMP 0x6be00000U
114 #define ALPHA_RETURN 0x6bfa8001U
116 #define ALPHA_FTOIT 0x701f0e00U
117 #define ALPHA_FTOIS 0x701f0f00U
119 #define ALPHA_SEXTB 0x73e00000U
120 #define ALPHA_SEXTW 0x73e00020U
121 #define ALPHA_CTPOP 0x73e00600U
122 #define ALPHA_CTLZ 0x73e00640U
123 #define ALPHA_CTTZ 0x73e00660U
125 #define ALPHA_LDS 0x88000000U
126 #define ALPHA_LDT 0x8c000000U
127 #define ALPHA_STS 0x98000000U
128 #define ALPHA_STT 0x9c000000U
130 #define ALPHA_LDL 0xa0000000U
131 #define ALPHA_LDQ 0xa4000000U
132 #define ALPHA_STL 0xb0000000U
133 #define ALPHA_STQ 0xb4000000U
135 #define ALPHA_BR 0xc3e00000U
137 #define ALPHA_BLBC 0xe0000000U
138 #define ALPHA_BEQ 0xe4000000U
139 #define ALPHA_BLT 0xe8000000U
140 #define ALPHA_BLE 0xec000000U
141 #define ALPHA_BLBS 0xf0000000U
142 #define ALPHA_BNE 0xf4000000U
143 #define ALPHA_BGE 0xf8000000U
144 #define ALPHA_BGT 0xfc000000U
146 static bool attr_w cgen_memory(struct codegen_context *ctx, uint32_t mc, unsigned ra, unsigned rb, int64_t imm)
148 if (unlikely(imm < -0x8000) || unlikely(imm >= 0x8000))
149 internal(file_line, "cgen_memory: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
157 static bool attr_w cgen_operate(struct codegen_context *ctx, uint32_t mc, unsigned ra, uint8_t *rb, unsigned rc)
159 if (unlikely(ra >= 0x20) || unlikely(rc >= 0x20))
164 mc |= (uint32_t)rb[0] << 16;
165 } else if (rb[0] == ARG_IMM) {
166 int64_t imm = get_imm(&rb[1]);
167 if (unlikely(imm < 0) || unlikely(imm >= 256))
168 internal(file_line, "cgen_operate: invalid literal %"PRIxMAX"", (uintmax_t)imm);
169 mc |= ALPHA_OPERATE_LITERAL;
170 mc |= (uint32_t)(imm & 0xff) << 13;
173 internal(file_line, "cgen_operate: invalid args %02x, %02x, %02x", ra, rb[0], rc);
179 static bool attr_w cgen_fp_operate(struct codegen_context *ctx, uint32_t mc, unsigned ra, unsigned rb, unsigned rc)
181 if (unlikely(ra >= 0x40) || unlikely(rb >= 0x40) || unlikely(rc >= 0x40))
182 internal(file_line, "cgen_fp_operate: invalid args %02x, %02x, %02x", ra, rb, rc);
183 mc |= (ra & 0x1f) << 21;
185 mc |= (rb & 0x1f) << 16;
190 static bool attr_w cgen_branch(struct codegen_context *ctx, uint32_t mc, unsigned ra)
193 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
198 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
203 uint8_t *arg1 = ctx->code_position;
204 uint8_t *arg2 = arg1 + arg_size(*arg1);
205 ctx->code_position = arg2 + arg_size(*arg2);
206 if (arg1[0] < 0x20) {
207 if (arg2[0] == ARG_IMM) {
208 imm = get_imm(&arg2[1]);
209 if (imm >= -0x8000L && imm < 0x8000L) {
210 g(cgen_memory(ctx, ALPHA_LDA, arg1[0], R_ZERO, imm));
213 if (!(imm & 0xffff) && imm >= -0x80000000L && imm < 0x80000000L) {
214 g(cgen_memory(ctx, ALPHA_LDAH, arg1[0], R_ZERO, imm / 0x10000));
217 internal(file_line, "cgen_mov: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
219 if (arg2[0] == ARG_ADDRESS_1) {
220 imm = get_imm(&arg2[2]);
223 if (unlikely(!ARCH_HAS_BWX))
228 if (unlikely(!ARCH_HAS_BWX))
238 g(cgen_memory(ctx, mc, *arg1, arg2[1], imm));
241 if (arg2[0] < 0x20) {
242 if (unlikely(size != OP_SIZE_NATIVE))
243 internal(file_line, "cgen_mov: invalid size %u", size);
244 g(cgen_operate(ctx, ALPHA_BIS, R_ZERO, arg2, arg1[0]));
247 if (arg2[0] < 0x40) {
248 mc = size == OP_SIZE_4 ? ALPHA_FTOIS : ALPHA_FTOIT;
249 g(cgen_fp_operate(ctx, mc, arg2[0], 0x1f, arg1[0]));
254 if (arg1[0] < 0x40) {
255 if (arg2[0] < 0x20) {
256 mc = size == OP_SIZE_4 ? ALPHA_ITOFS : ALPHA_ITOFT;
257 g(cgen_fp_operate(ctx, mc, arg2[0], 0x1f, arg1[0]));
262 if (arg2[0] == ARG_ADDRESS_1) {
263 imm = get_imm(&arg2[2]);
265 case OP_SIZE_4: mc = ALPHA_LDS; break;
266 case OP_SIZE_8: mc = ALPHA_LDT; break;
267 default: goto invalid;
269 g(cgen_memory(ctx, mc, *arg1 & 0x1f, arg2[1], imm));
274 if (arg1[0] == ARG_ADDRESS_1) {
275 if (arg2[0] == ARG_IMM) {
276 imm = get_imm(&arg2[1]);
277 if (unlikely(imm != 0))
281 if (arg2[0] < 0x20) {
282 imm = get_imm(&arg1[2]);
285 if (unlikely(!ARCH_HAS_BWX))
290 if (unlikely(!ARCH_HAS_BWX))
303 g(cgen_memory(ctx, mc, *arg2, arg1[1], imm));
306 if (arg2[0] < 0x40) {
307 imm = get_imm(&arg1[2]);
309 case OP_SIZE_4: mc = ALPHA_STS; break;
310 case OP_SIZE_8: mc = ALPHA_STT; break;
311 default: goto invalid;
313 g(cgen_memory(ctx, mc, *arg2 & 0x1f, arg1[1], imm));
319 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
323 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
325 uint8_t *arg1, *arg2;
326 if (size == OP_SIZE_NATIVE) {
327 g(cgen_mov(ctx, size));
330 arg1 = ctx->code_position;
331 arg2 = arg1 + arg_size(*arg1);
332 ctx->code_position = arg2 + arg_size(*arg2);
334 if (reg_is_fp(*arg1) && reg_is_fp(*arg2) && size == OP_SIZE_4) {
335 g(cgen_fp_operate(ctx, ALPHA_CVTLQ, 0x1f, *arg2, *arg1));
339 if (unlikely(*arg1 >= 0x20))
342 if (*arg2 == ARG_ADDRESS_1) {
343 if (unlikely(size < OP_SIZE_4))
345 g(cgen_memory(ctx, ALPHA_LDL, *arg1, arg2[1], get_imm(&arg2[2])));
352 if (unlikely(!ARCH_HAS_BWX))
357 if (unlikely(!ARCH_HAS_BWX))
367 g(cgen_operate(ctx, mc, 0x1f, arg2, *arg1));
372 internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, *arg1, *arg2);
376 static bool attr_w cgen_mov_u(struct codegen_context *ctx)
378 uint8_t *arg1, *arg2;
379 arg1 = ctx->code_position;
380 arg2 = arg1 + arg_size(*arg1);
381 ctx->code_position = arg2 + arg_size(*arg2);
383 if (*arg1 < 0x20 && *arg2 == ARG_ADDRESS_1) {
384 g(cgen_memory(ctx, ALPHA_LDQ_U, *arg1, arg2[1], get_imm(&arg2[2])));
386 } else if (*arg1 == ARG_ADDRESS_1 && *arg2 < 0x20) {
387 g(cgen_memory(ctx, ALPHA_STQ_U, *arg2, arg1[1], get_imm(&arg1[2])));
391 internal(file_line, "cgen_mov_u: invalid parameters %02x, %02x", *arg1, *arg2);
395 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
399 uint8_t *arg1 = ctx->code_position;
400 uint8_t *arg2 = arg1 + arg_size(*arg1);
401 uint8_t *arg3 = arg2 + arg_size(*arg2);
402 ctx->code_position = arg3 + arg_size(*arg3);
404 case COND_B: mc = ALPHA_CMPULT; break;
405 case COND_AE: mc = ALPHA_CMPULE; swap = true; break;
406 case COND_E: mc = ALPHA_CMPEQ; break;
407 /*case COND_NE: mc = ALPHA_XOR; break;*/
408 case COND_BE: mc = ALPHA_CMPULE; break;
409 case COND_A: mc = ALPHA_CMPULT; swap = true; break;
410 case COND_L: mc = ALPHA_CMPLT; break;
411 case COND_GE: mc = ALPHA_CMPLE; swap = true; break;
412 case COND_LE: mc = ALPHA_CMPLE; break;
413 case COND_G: mc = ALPHA_CMPLT; swap = true; break;
414 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
418 if (arg3[0] == ARG_IMM)
419 internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
424 g(cgen_operate(ctx, mc, *arg2, arg3, *arg1));
428 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
431 uint8_t *arg1 = ctx->code_position;
432 uint8_t *arg2 = arg1 + arg_size(*arg1);
433 uint8_t *arg3 = arg2 + arg_size(*arg2);
434 ctx->code_position = arg3 + arg_size(*arg3);
435 if (arg3[0] == ARG_IMM) {
436 int64_t imm = get_imm(&arg3[1]);
439 imm = -(uint64_t)imm;
442 if (imm >= -0x8000 && imm < 0x8000) {
443 g(cgen_memory(ctx, ALPHA_LDA, arg1[0], arg2[0], imm));
446 if (!(imm & 0xffff) && imm >= -0x80000000L && imm < 0x80000000L) {
447 g(cgen_memory(ctx, ALPHA_LDAH, arg1[0], arg2[0], imm / 0x10000));
450 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
454 case ALU_ADD: mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL; break;
455 case ALU_OR: mc = ALPHA_BIS; break;
456 case ALU_AND: mc = ALPHA_AND; break;
457 case ALU_SUB: mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL; break;
458 case ALU_XOR: mc = ALPHA_XOR; break;
459 case ALU_ORN: mc = ALPHA_ORNOT; break;
460 case ALU_ANDN: mc = ALPHA_ANDNOT; break;
461 case ALU_XORN: mc = ALPHA_EQV; break;
462 case ALU_MUL: mc = size == OP_SIZE_8 ? ALPHA_MULQ : ALPHA_MULL; break;
463 case ALU_UMULH: mc = ALPHA_UMULH; break;
464 case ALU_EXTBL: mc = ALPHA_EXTBL; break;
465 case ALU_EXTWL: mc = ALPHA_EXTWL; break;
466 case ALU_EXTLL: mc = ALPHA_EXTLL; break;
467 case ALU_EXTLH: mc = ALPHA_EXTLH; break;
468 case ALU_INSBL: mc = ALPHA_INSBL; break;
469 case ALU_MSKBL: mc = ALPHA_MSKBL; break;
470 case ALU_ZAP: mc = ALPHA_ZAP; break;
471 case ALU_ZAPNOT:mc = ALPHA_ZAPNOT; break;
472 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
474 if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
475 uint8_t *arg_swp = arg3;
479 if (arg2[0] == ARG_SHIFTED_REGISTER && (arg2[1] == (ARG_SHIFT_LSL | 0) || arg2[1] == (ARG_SHIFT_LSL | 2) || arg2[1] == (ARG_SHIFT_LSL | 3)) && (alu == ALU_ADD || alu == ALU_SUB)) {
480 if (arg2[1] == (ARG_SHIFT_LSL | 0) && alu == ALU_ADD)
481 mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL;
482 else if (arg2[1] == (ARG_SHIFT_LSL | 0) && alu == ALU_SUB)
483 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
484 else if (arg2[1] == (ARG_SHIFT_LSL | 2) && alu == ALU_ADD)
485 mc = size == OP_SIZE_8 ? ALPHA_S4ADDQ : ALPHA_S4ADDL;
486 else if (arg2[1] == (ARG_SHIFT_LSL | 2) && alu == ALU_SUB)
487 mc = size == OP_SIZE_8 ? ALPHA_S4SUBQ : ALPHA_S4SUBL;
488 else if (arg2[1] == (ARG_SHIFT_LSL | 3) && alu == ALU_ADD)
489 mc = size == OP_SIZE_8 ? ALPHA_S8ADDQ : ALPHA_S8ADDL;
490 else if (arg2[1] == (ARG_SHIFT_LSL | 3) && alu == ALU_SUB)
491 mc = size == OP_SIZE_8 ? ALPHA_S8SUBQ : ALPHA_S8SUBL;
493 internal(file_line, "cgen_alu: invalid shifted register operation: %02x, %u", arg2[1], alu);
496 g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
500 static bool attr_w cgen_alu_trap(struct codegen_context *ctx, unsigned size, unsigned alu)
504 uint8_t *arg1 = ctx->code_position;
505 uint8_t *arg2 = arg1 + arg_size(*arg1);
506 uint8_t *arg3 = arg2 + arg_size(*arg2);
507 ctx->code_position = arg3 + arg_size(*arg3);
508 trap_label = cget_four(ctx);
510 case ALU_ADD: mc = size == OP_SIZE_8 ? ALPHA_ADDQ_V : ALPHA_ADDL_V; break;
511 case ALU_SUB: mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V; break;
512 case ALU_MUL: mc = size == OP_SIZE_8 ? ALPHA_MULQ_V : ALPHA_MULL_V; break;
513 default: internal(file_line, "cgen_alu_trap: invalid alu trap %u", alu);
515 g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
516 g(cgen_trap(ctx, trap_label));
517 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
518 cgen_four(ALPHA_TRAPB);
522 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
525 uint32_t trap_label = 0; /* avoid warning */
526 uint8_t one_imm[9] = { ARG_IMM, 1, 0, 0, 0, 0, 0, 0, 0 };
527 uint8_t *arg1 = ctx->code_position;
528 uint8_t *arg2 = arg1 + arg_size(*arg1);
529 ctx->code_position = arg2 + arg_size(*arg2);
531 trap_label = cget_four(ctx);
536 g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
540 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
542 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
543 g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
547 mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL;
549 mc = size == OP_SIZE_8 ? ALPHA_ADDQ_V : ALPHA_ADDL_V;
550 g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
554 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
556 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
557 g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
561 g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
565 g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
569 g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
572 internal(file_line, "cgen_alu1: invalid alu %u", alu);
575 g(cgen_trap(ctx, trap_label));
576 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
577 cgen_four(ALPHA_TRAPB);
582 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned alu)
585 uint8_t *arg1 = ctx->code_position;
586 uint8_t *arg2 = arg1 + arg_size(*arg1);
587 uint8_t *arg3 = arg2 + arg_size(*arg2);
588 ctx->code_position = arg3 + arg_size(*arg3);
590 case ROT_SHL: mc = ALPHA_SLL; break;
591 case ROT_SHR: mc = ALPHA_SRL; break;
592 case ROT_SAR: mc = ALPHA_SRA; break;
593 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
595 g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
599 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
602 uint8_t *arg1 = ctx->code_position;
603 uint8_t *arg2 = arg1 + arg_size(*arg1);
604 uint8_t *arg3 = arg2 + arg_size(*arg2);
605 uint8_t *arg4 = arg3 + arg_size(*arg3);
606 ctx->code_position = arg4 + arg_size(*arg4);
611 mc = ALPHA_CMOVLT; break;
615 mc = ALPHA_CMOVGE; break;
617 mc = ALPHA_CMOVEQ; break;
619 mc = ALPHA_CMOVNE; break;
622 mc = ALPHA_CMOVLE; break;
625 mc = ALPHA_CMOVGT; break;
627 mc = ALPHA_CMOVLBC; break;
629 mc = ALPHA_CMOVLBS; break;
631 internal(file_line, "cgen_movr: invalid condition %u", aux);
633 if (unlikely(arg1[0] != arg2[0]))
634 internal(file_line, "cgen_movr: invalid arguments");
635 g(cgen_operate(ctx, mc, arg3[0], arg4, arg1[0]));
639 static bool attr_w cgen_fp_cmp_trap(struct codegen_context *ctx, unsigned aux)
644 uint8_t *arg1 = ctx->code_position;
645 uint8_t *arg2 = arg1 + arg_size(*arg1);
646 uint8_t *arg3 = arg2 + arg_size(*arg2);
647 ctx->code_position = arg3 + arg_size(*arg3);
648 trap_label = cget_four(ctx);
650 case FP_COND_E: mc = ALPHA_CMPTEQ; break;
651 case FP_COND_A: mc = ALPHA_CMPTLT; swap = true; break;
652 case FP_COND_BE: mc = ALPHA_CMPTLE; break;
653 case FP_COND_B: mc = ALPHA_CMPTLT; break;
654 case FP_COND_AE: mc = ALPHA_CMPTLE; swap = true; break;
655 default: internal(file_line, "cgen_fp_cmp_trap: invalid condition %u", aux);
663 g(cgen_fp_operate(ctx, mc, arg2[0], arg3[0], arg1[0]));
664 g(cgen_trap(ctx, trap_label));
665 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
666 cgen_four(ALPHA_TRAPB);
670 static bool attr_w cgen_fp_cmp_unordered(struct codegen_context *ctx)
673 uint8_t *arg1 = ctx->code_position;
674 uint8_t *arg2 = arg1 + arg_size(*arg1);
675 uint8_t *arg3 = arg2 + arg_size(*arg2);
676 ctx->code_position = arg3 + arg_size(*arg3);
677 mc = ALPHA_CMPTUN_SU;
678 g(cgen_fp_operate(ctx, mc, arg2[0], arg3[0], arg1[0]));
679 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
680 cgen_four(ALPHA_TRAPB);
684 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
687 uint8_t *arg1 = ctx->code_position;
688 uint8_t *arg2 = arg1 + arg_size(*arg1);
689 uint8_t *arg3 = arg2 + arg_size(*arg2);
690 ctx->code_position = arg3 + arg_size(*arg3);
692 case FP_ALU_ADD: mc = op_size == OP_SIZE_4 ? ALPHA_ADDS_SU : ALPHA_ADDT_SU; break;
693 case FP_ALU_SUB: mc = op_size == OP_SIZE_4 ? ALPHA_SUBS_SU : ALPHA_SUBT_SU; break;
694 case FP_ALU_MUL: mc = op_size == OP_SIZE_4 ? ALPHA_MULS_SU : ALPHA_MULT_SU; break;
695 case FP_ALU_DIV: mc = op_size == OP_SIZE_4 ? ALPHA_DIVS_SU : ALPHA_DIVT_SU; break;
696 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
698 g(cgen_fp_operate(ctx, mc, arg2[0], arg3[0], arg1[0]));
699 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
700 cgen_four(ALPHA_TRAPB);
704 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned attr_unused op_size, unsigned aux)
706 uint8_t *arg1 = ctx->code_position;
707 uint8_t *arg2 = arg1 + arg_size(*arg1);
708 ctx->code_position = arg2 + arg_size(*arg2);
710 case FP_ALU1_NEG: g(cgen_fp_operate(ctx, ALPHA_CPYSN, arg2[0], arg2[0], arg1[0]));
712 case FP_ALU1_SQRT: g(cgen_fp_operate(ctx, op_size == OP_SIZE_4 ? ALPHA_SQRTS_SU : ALPHA_SQRTT_SU, 0, arg2[0], arg1[0]));
713 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
714 cgen_four(ALPHA_TRAPB);
716 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
721 static bool attr_w cgen_fp_to_int64_trap(struct codegen_context *ctx)
725 uint8_t *arg1 = ctx->code_position;
726 uint8_t *arg2 = arg1 + arg_size(*arg1);
727 ctx->code_position = arg2 + arg_size(*arg2);
728 trap_label = cget_four(ctx);
731 g(cgen_fp_operate(ctx, mc, 0x31, arg2[0], arg1[0]));
732 g(cgen_trap(ctx, trap_label));
733 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
734 cgen_four(ALPHA_TRAPB);
738 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
741 uint8_t *arg1 = ctx->code_position;
742 uint8_t *arg2 = arg1 + arg_size(*arg1);
743 ctx->code_position = arg2 + arg_size(*arg2);
744 mc = fp_op_size == OP_SIZE_4 ? ALPHA_CVTQS : ALPHA_CVTQT;
745 g(cgen_fp_operate(ctx, mc, 0x31, arg2[0], arg1[0]));
746 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
747 cgen_four(ALPHA_TRAPB);
751 static bool attr_w cgen_fp_int64_to_int32_trap(struct codegen_context *ctx)
755 uint8_t *arg1 = ctx->code_position;
756 uint8_t *arg2 = arg1 + arg_size(*arg1);
757 ctx->code_position = arg2 + arg_size(*arg2);
758 trap_label = cget_four(ctx);
761 g(cgen_fp_operate(ctx, mc, 0x31, arg2[0], arg1[0]));
762 g(cgen_trap(ctx, trap_label));
763 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
764 cgen_four(ALPHA_TRAPB);
769 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux)
772 uint8_t reg = cget_one(ctx);
777 mc = ALPHA_BLT; break;
781 mc = ALPHA_BGE; break;
783 mc = ALPHA_BEQ; break;
785 mc = ALPHA_BNE; break;
788 mc = ALPHA_BLE; break;
791 mc = ALPHA_BGT; break;
793 mc = ALPHA_BLBC; break;
795 mc = ALPHA_BLBS; break;
797 internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
799 g(cgen_branch(ctx, mc, reg));
803 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
806 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2) - 1;
807 switch (reloc->length) {
809 if (unlikely(offs < -0x00100000) || unlikely(offs >= 0x00100000))
811 memcpy(&mc, ctx->mcode + reloc->position, 4);
813 mc |= offs & 0x001fffffU;
814 memcpy(ctx->mcode + reloc->position, &mc, 4);
817 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
822 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
825 /*debug("insn: %08x", insn);*/
826 if (unlikely(insn_writes_flags(insn)))
828 switch (insn_opcode(insn)) {
836 cgen_four(ALPHA_RETURN);
838 case INSN_CALL_INDIRECT:
840 if (unlikely(reg != R_T12))
841 internal(file_line, "cgen_insn: invalid call register %u", (unsigned)reg);
842 cgen_four(ALPHA_JSR_T12);
845 g(cgen_mov(ctx, insn_op_size(insn)));
848 g(cgen_movsx(ctx, insn_op_size(insn)));
851 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
855 case INSN_CMP_DEST_REG:
856 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
858 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
861 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
863 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
866 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
868 g(cgen_alu_trap(ctx, insn_op_size(insn), insn_aux(insn)));
871 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
873 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
876 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
878 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
881 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
883 g(cgen_rot(ctx, insn_aux(insn)));
886 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
888 g(cgen_movr(ctx, insn_aux(insn)));
890 case INSN_FP_CMP_DEST_REG_TRAP:
891 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
893 g(cgen_fp_cmp_trap(ctx, insn_aux(insn)));
895 case INSN_FP_CMP_UNORDERED_DEST_REG:
896 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
898 g(cgen_fp_cmp_unordered(ctx));
901 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
903 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
906 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
908 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
910 case INSN_FP_TO_INT64_TRAP:
911 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
913 g(cgen_fp_to_int64_trap(ctx));
915 case INSN_FP_FROM_INT64:
916 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
918 g(cgen_fp_from_int(ctx, insn_op_size(insn)));
920 case INSN_FP_INT64_TO_INT32_TRAP:
921 g(cgen_fp_int64_to_int32_trap(ctx));
924 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
928 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
930 g(cgen_jmp_reg(ctx, insn_aux(insn)));
932 case INSN_JMP_INDIRECT:
934 cgen_four(ALPHA_JMP + ((uint32_t)reg << 16));
941 internal(file_line, "cgen_insn: invalid insn %08x", insn);