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 (reg_is_fp(arg2[0])) {
248 mc = size == OP_SIZE_4 ? ALPHA_FTOIS : ALPHA_FTOIT;
249 g(cgen_fp_operate(ctx, mc, arg2[0], 0x1f, arg1[0]));
254 if (reg_is_fp(arg1[0])) {
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]));
260 if (reg_is_fp(arg2[0])) {
261 g(cgen_fp_operate(ctx, ALPHA_CPYS, arg2[0], arg2[0], arg1[0]));
264 if (arg2[0] == ARG_ADDRESS_1) {
265 imm = get_imm(&arg2[2]);
267 case OP_SIZE_4: mc = ALPHA_LDS; break;
268 case OP_SIZE_8: mc = ALPHA_LDT; break;
269 default: goto invalid;
271 g(cgen_memory(ctx, mc, *arg1 & 0x1f, arg2[1], imm));
276 if (arg1[0] == ARG_ADDRESS_1) {
277 if (arg2[0] == ARG_IMM) {
278 imm = get_imm(&arg2[1]);
279 if (unlikely(imm != 0))
283 if (arg2[0] < 0x20) {
284 imm = get_imm(&arg1[2]);
287 if (unlikely(!ARCH_HAS_BWX))
292 if (unlikely(!ARCH_HAS_BWX))
305 g(cgen_memory(ctx, mc, *arg2, arg1[1], imm));
308 if (reg_is_fp(arg2[0])) {
309 imm = get_imm(&arg1[2]);
311 case OP_SIZE_4: mc = ALPHA_STS; break;
312 case OP_SIZE_8: mc = ALPHA_STT; break;
313 default: goto invalid;
315 g(cgen_memory(ctx, mc, *arg2 & 0x1f, arg1[1], imm));
321 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
325 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
327 uint8_t *arg1, *arg2;
328 if (size == OP_SIZE_NATIVE) {
329 g(cgen_mov(ctx, size));
332 arg1 = ctx->code_position;
333 arg2 = arg1 + arg_size(*arg1);
334 ctx->code_position = arg2 + arg_size(*arg2);
336 if (reg_is_fp(*arg1) && reg_is_fp(*arg2) && size == OP_SIZE_4) {
337 g(cgen_fp_operate(ctx, ALPHA_CVTLQ, 0x1f, *arg2, *arg1));
341 if (unlikely(*arg1 >= 0x20))
344 if (*arg2 == ARG_ADDRESS_1) {
345 if (unlikely(size < OP_SIZE_4))
347 g(cgen_memory(ctx, ALPHA_LDL, *arg1, arg2[1], get_imm(&arg2[2])));
354 if (unlikely(!ARCH_HAS_BWX))
359 if (unlikely(!ARCH_HAS_BWX))
369 g(cgen_operate(ctx, mc, 0x1f, arg2, *arg1));
374 internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, *arg1, *arg2);
378 static bool attr_w cgen_mov_u(struct codegen_context *ctx)
380 uint8_t *arg1, *arg2;
381 arg1 = ctx->code_position;
382 arg2 = arg1 + arg_size(*arg1);
383 ctx->code_position = arg2 + arg_size(*arg2);
385 if (*arg1 < 0x20 && *arg2 == ARG_ADDRESS_1) {
386 g(cgen_memory(ctx, ALPHA_LDQ_U, *arg1, arg2[1], get_imm(&arg2[2])));
388 } else if (*arg1 == ARG_ADDRESS_1 && *arg2 < 0x20) {
389 g(cgen_memory(ctx, ALPHA_STQ_U, *arg2, arg1[1], get_imm(&arg1[2])));
393 internal(file_line, "cgen_mov_u: invalid parameters %02x, %02x", *arg1, *arg2);
397 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
401 uint8_t *arg1 = ctx->code_position;
402 uint8_t *arg2 = arg1 + arg_size(*arg1);
403 uint8_t *arg3 = arg2 + arg_size(*arg2);
404 ctx->code_position = arg3 + arg_size(*arg3);
406 case COND_B: mc = ALPHA_CMPULT; break;
407 case COND_AE: mc = ALPHA_CMPULE; swap = true; break;
408 case COND_E: mc = ALPHA_CMPEQ; break;
409 /*case COND_NE: mc = ALPHA_XOR; break;*/
410 case COND_BE: mc = ALPHA_CMPULE; break;
411 case COND_A: mc = ALPHA_CMPULT; swap = true; break;
412 case COND_L: mc = ALPHA_CMPLT; break;
413 case COND_GE: mc = ALPHA_CMPLE; swap = true; break;
414 case COND_LE: mc = ALPHA_CMPLE; break;
415 case COND_G: mc = ALPHA_CMPLT; swap = true; break;
416 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
420 if (arg3[0] == ARG_IMM)
421 internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
426 g(cgen_operate(ctx, mc, *arg2, arg3, *arg1));
430 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
433 uint8_t *arg1 = ctx->code_position;
434 uint8_t *arg2 = arg1 + arg_size(*arg1);
435 uint8_t *arg3 = arg2 + arg_size(*arg2);
436 ctx->code_position = arg3 + arg_size(*arg3);
437 if (arg3[0] == ARG_IMM) {
438 int64_t imm = get_imm(&arg3[1]);
441 imm = -(uint64_t)imm;
444 if (imm >= -0x8000 && imm < 0x8000) {
445 g(cgen_memory(ctx, ALPHA_LDA, arg1[0], arg2[0], imm));
448 if (!(imm & 0xffff) && imm >= -0x80000000L && imm < 0x80000000L) {
449 g(cgen_memory(ctx, ALPHA_LDAH, arg1[0], arg2[0], imm / 0x10000));
452 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
456 case ALU_ADD: mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL; break;
457 case ALU_OR: mc = ALPHA_BIS; break;
458 case ALU_AND: mc = ALPHA_AND; break;
459 case ALU_SUB: mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL; break;
460 case ALU_XOR: mc = ALPHA_XOR; break;
461 case ALU_ORN: mc = ALPHA_ORNOT; break;
462 case ALU_ANDN: mc = ALPHA_ANDNOT; break;
463 case ALU_XORN: mc = ALPHA_EQV; break;
464 case ALU_MUL: mc = size == OP_SIZE_8 ? ALPHA_MULQ : ALPHA_MULL; break;
465 case ALU_UMULH: mc = ALPHA_UMULH; break;
466 case ALU_EXTBL: mc = ALPHA_EXTBL; break;
467 case ALU_EXTWL: mc = ALPHA_EXTWL; break;
468 case ALU_EXTLL: mc = ALPHA_EXTLL; break;
469 case ALU_EXTLH: mc = ALPHA_EXTLH; break;
470 case ALU_INSBL: mc = ALPHA_INSBL; break;
471 case ALU_MSKBL: mc = ALPHA_MSKBL; break;
472 case ALU_ZAP: mc = ALPHA_ZAP; break;
473 case ALU_ZAPNOT:mc = ALPHA_ZAPNOT; break;
474 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
476 if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
477 uint8_t *arg_swp = arg3;
481 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)) {
482 if (arg2[1] == (ARG_SHIFT_LSL | 0) && alu == ALU_ADD)
483 mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL;
484 else if (arg2[1] == (ARG_SHIFT_LSL | 0) && alu == ALU_SUB)
485 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
486 else if (arg2[1] == (ARG_SHIFT_LSL | 2) && alu == ALU_ADD)
487 mc = size == OP_SIZE_8 ? ALPHA_S4ADDQ : ALPHA_S4ADDL;
488 else if (arg2[1] == (ARG_SHIFT_LSL | 2) && alu == ALU_SUB)
489 mc = size == OP_SIZE_8 ? ALPHA_S4SUBQ : ALPHA_S4SUBL;
490 else if (arg2[1] == (ARG_SHIFT_LSL | 3) && alu == ALU_ADD)
491 mc = size == OP_SIZE_8 ? ALPHA_S8ADDQ : ALPHA_S8ADDL;
492 else if (arg2[1] == (ARG_SHIFT_LSL | 3) && alu == ALU_SUB)
493 mc = size == OP_SIZE_8 ? ALPHA_S8SUBQ : ALPHA_S8SUBL;
495 internal(file_line, "cgen_alu: invalid shifted register operation: %02x, %u", arg2[1], alu);
498 g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
502 static bool attr_w cgen_alu_trap(struct codegen_context *ctx, unsigned size, unsigned alu)
506 uint8_t *arg1 = ctx->code_position;
507 uint8_t *arg2 = arg1 + arg_size(*arg1);
508 uint8_t *arg3 = arg2 + arg_size(*arg2);
509 ctx->code_position = arg3 + arg_size(*arg3);
510 trap_label = cget_four(ctx);
512 case ALU_ADD: mc = size == OP_SIZE_8 ? ALPHA_ADDQ_V : ALPHA_ADDL_V; break;
513 case ALU_SUB: mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V; break;
514 case ALU_MUL: mc = size == OP_SIZE_8 ? ALPHA_MULQ_V : ALPHA_MULL_V; break;
515 default: internal(file_line, "cgen_alu_trap: invalid alu trap %u", alu);
517 g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
518 g(cgen_trap(ctx, trap_label));
519 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
520 cgen_four(ALPHA_TRAPB);
524 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
527 uint32_t trap_label = 0; /* avoid warning */
528 uint8_t one_imm[9] = { ARG_IMM, 1, 0, 0, 0, 0, 0, 0, 0 };
529 uint8_t *arg1 = ctx->code_position;
530 uint8_t *arg2 = arg1 + arg_size(*arg1);
531 ctx->code_position = arg2 + arg_size(*arg2);
533 trap_label = cget_four(ctx);
538 g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
542 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
544 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
545 g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
549 mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL;
551 mc = size == OP_SIZE_8 ? ALPHA_ADDQ_V : ALPHA_ADDL_V;
552 g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
556 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
558 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
559 g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
563 g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
567 g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
571 g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
574 internal(file_line, "cgen_alu1: invalid alu %u", alu);
577 g(cgen_trap(ctx, trap_label));
578 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
579 cgen_four(ALPHA_TRAPB);
584 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned alu)
587 uint8_t *arg1 = ctx->code_position;
588 uint8_t *arg2 = arg1 + arg_size(*arg1);
589 uint8_t *arg3 = arg2 + arg_size(*arg2);
590 ctx->code_position = arg3 + arg_size(*arg3);
592 case ROT_SHL: mc = ALPHA_SLL; break;
593 case ROT_SHR: mc = ALPHA_SRL; break;
594 case ROT_SAR: mc = ALPHA_SRA; break;
595 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
597 g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
601 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
604 uint8_t *arg1 = ctx->code_position;
605 uint8_t *arg2 = arg1 + arg_size(*arg1);
606 uint8_t *arg3 = arg2 + arg_size(*arg2);
607 uint8_t *arg4 = arg3 + arg_size(*arg3);
608 ctx->code_position = arg4 + arg_size(*arg4);
613 mc = ALPHA_CMOVLT; break;
617 mc = ALPHA_CMOVGE; break;
619 mc = ALPHA_CMOVEQ; break;
621 mc = ALPHA_CMOVNE; break;
624 mc = ALPHA_CMOVLE; break;
627 mc = ALPHA_CMOVGT; break;
629 mc = ALPHA_CMOVLBC; break;
631 mc = ALPHA_CMOVLBS; break;
633 internal(file_line, "cgen_movr: invalid condition %u", aux);
635 if (unlikely(arg1[0] != arg2[0]))
636 internal(file_line, "cgen_movr: invalid arguments");
637 g(cgen_operate(ctx, mc, arg3[0], arg4, arg1[0]));
641 static bool attr_w cgen_fp_cmp_trap(struct codegen_context *ctx, unsigned aux)
646 uint8_t *arg1 = ctx->code_position;
647 uint8_t *arg2 = arg1 + arg_size(*arg1);
648 uint8_t *arg3 = arg2 + arg_size(*arg2);
649 ctx->code_position = arg3 + arg_size(*arg3);
650 trap_label = cget_four(ctx);
652 case FP_COND_E: mc = ALPHA_CMPTEQ; break;
653 case FP_COND_A: mc = ALPHA_CMPTLT; swap = true; break;
654 case FP_COND_BE: mc = ALPHA_CMPTLE; break;
655 case FP_COND_B: mc = ALPHA_CMPTLT; break;
656 case FP_COND_AE: mc = ALPHA_CMPTLE; swap = true; break;
657 default: internal(file_line, "cgen_fp_cmp_trap: invalid condition %u", aux);
665 g(cgen_fp_operate(ctx, mc, arg2[0], arg3[0], arg1[0]));
666 g(cgen_trap(ctx, trap_label));
667 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
668 cgen_four(ALPHA_TRAPB);
672 static bool attr_w cgen_fp_cmp_unordered(struct codegen_context *ctx)
675 uint8_t *arg1 = ctx->code_position;
676 uint8_t *arg2 = arg1 + arg_size(*arg1);
677 uint8_t *arg3 = arg2 + arg_size(*arg2);
678 ctx->code_position = arg3 + arg_size(*arg3);
679 mc = ALPHA_CMPTUN_SU;
680 g(cgen_fp_operate(ctx, mc, arg2[0], arg3[0], arg1[0]));
681 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
682 cgen_four(ALPHA_TRAPB);
686 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
689 uint8_t *arg1 = ctx->code_position;
690 uint8_t *arg2 = arg1 + arg_size(*arg1);
691 uint8_t *arg3 = arg2 + arg_size(*arg2);
692 ctx->code_position = arg3 + arg_size(*arg3);
694 case FP_ALU_ADD: mc = op_size == OP_SIZE_4 ? ALPHA_ADDS_SU : ALPHA_ADDT_SU; break;
695 case FP_ALU_SUB: mc = op_size == OP_SIZE_4 ? ALPHA_SUBS_SU : ALPHA_SUBT_SU; break;
696 case FP_ALU_MUL: mc = op_size == OP_SIZE_4 ? ALPHA_MULS_SU : ALPHA_MULT_SU; break;
697 case FP_ALU_DIV: mc = op_size == OP_SIZE_4 ? ALPHA_DIVS_SU : ALPHA_DIVT_SU; break;
698 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
700 g(cgen_fp_operate(ctx, mc, arg2[0], arg3[0], arg1[0]));
701 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
702 cgen_four(ALPHA_TRAPB);
706 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned attr_unused op_size, unsigned aux)
708 uint8_t *arg1 = ctx->code_position;
709 uint8_t *arg2 = arg1 + arg_size(*arg1);
710 ctx->code_position = arg2 + arg_size(*arg2);
712 case FP_ALU1_NEG: g(cgen_fp_operate(ctx, ALPHA_CPYSN, arg2[0], arg2[0], arg1[0]));
714 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]));
715 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
716 cgen_four(ALPHA_TRAPB);
718 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
723 static bool attr_w cgen_fp_to_int64_trap(struct codegen_context *ctx)
727 uint8_t *arg1 = ctx->code_position;
728 uint8_t *arg2 = arg1 + arg_size(*arg1);
729 ctx->code_position = arg2 + arg_size(*arg2);
730 trap_label = cget_four(ctx);
733 g(cgen_fp_operate(ctx, mc, 0x31, arg2[0], arg1[0]));
734 g(cgen_trap(ctx, trap_label));
735 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
736 cgen_four(ALPHA_TRAPB);
740 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
743 uint8_t *arg1 = ctx->code_position;
744 uint8_t *arg2 = arg1 + arg_size(*arg1);
745 ctx->code_position = arg2 + arg_size(*arg2);
746 mc = fp_op_size == OP_SIZE_4 ? ALPHA_CVTQS : ALPHA_CVTQT;
747 g(cgen_fp_operate(ctx, mc, 0x31, arg2[0], arg1[0]));
748 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
749 cgen_four(ALPHA_TRAPB);
753 static bool attr_w cgen_fp_int64_to_int32_trap(struct codegen_context *ctx)
757 uint8_t *arg1 = ctx->code_position;
758 uint8_t *arg2 = arg1 + arg_size(*arg1);
759 ctx->code_position = arg2 + arg_size(*arg2);
760 trap_label = cget_four(ctx);
763 g(cgen_fp_operate(ctx, mc, 0x31, arg2[0], arg1[0]));
764 g(cgen_trap(ctx, trap_label));
765 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
766 cgen_four(ALPHA_TRAPB);
771 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux)
774 uint8_t reg = cget_one(ctx);
779 mc = ALPHA_BLT; break;
783 mc = ALPHA_BGE; break;
785 mc = ALPHA_BEQ; break;
787 mc = ALPHA_BNE; break;
790 mc = ALPHA_BLE; break;
793 mc = ALPHA_BGT; break;
795 mc = ALPHA_BLBC; break;
797 mc = ALPHA_BLBS; break;
799 internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
801 g(cgen_branch(ctx, mc, reg));
805 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
808 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2) - 1;
809 switch (reloc->length) {
811 if (unlikely(offs < -0x00100000) || unlikely(offs >= 0x00100000))
813 memcpy(&mc, ctx->mcode + reloc->position, 4);
815 mc |= offs & 0x001fffffU;
816 memcpy(ctx->mcode + reloc->position, &mc, 4);
819 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
824 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
827 /*debug("insn: %08x", insn);*/
828 if (unlikely(insn_writes_flags(insn)))
830 switch (insn_opcode(insn)) {
838 cgen_four(ALPHA_RETURN);
840 case INSN_CALL_INDIRECT:
842 if (unlikely(reg != R_T12))
843 internal(file_line, "cgen_insn: invalid call register %u", (unsigned)reg);
844 cgen_four(ALPHA_JSR_T12);
847 g(cgen_mov(ctx, insn_op_size(insn)));
850 g(cgen_movsx(ctx, insn_op_size(insn)));
853 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
857 case INSN_CMP_DEST_REG:
858 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
860 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
863 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
865 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
868 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
870 g(cgen_alu_trap(ctx, insn_op_size(insn), insn_aux(insn)));
873 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
875 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
878 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
880 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
883 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
885 g(cgen_rot(ctx, insn_aux(insn)));
888 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
890 g(cgen_movr(ctx, insn_aux(insn)));
892 case INSN_FP_CMP_DEST_REG_TRAP:
893 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
895 g(cgen_fp_cmp_trap(ctx, insn_aux(insn)));
897 case INSN_FP_CMP_UNORDERED_DEST_REG:
898 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
900 g(cgen_fp_cmp_unordered(ctx));
903 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
905 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
908 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
910 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
912 case INSN_FP_TO_INT64_TRAP:
913 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
915 g(cgen_fp_to_int64_trap(ctx));
917 case INSN_FP_FROM_INT64:
918 if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
920 g(cgen_fp_from_int(ctx, insn_op_size(insn)));
922 case INSN_FP_INT64_TO_INT32_TRAP:
923 g(cgen_fp_int64_to_int32_trap(ctx));
926 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
930 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
932 g(cgen_jmp_reg(ctx, insn_aux(insn)));
934 case INSN_JMP_INDIRECT:
936 cgen_four(ALPHA_JMP + ((uint32_t)reg << 16));
943 internal(file_line, "cgen_insn: invalid insn %08x", insn);