don't merge variables with different "must_be_flat" to the same slot
[ajla.git] / c2-alpha.inc
blob91e7677aab6f743856c1730653b016f92f4af795
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  */
19 #define 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);
150         mc |= ra << 21;
151         mc |= rb << 16;
152         mc |= imm & 0xffff;
153         cgen_four(mc);
154         return true;
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))
160                 goto invalid;
161         mc |= ra << 21;
162         mc |= rc;
163         if (rb[0] < 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;
171         } else {
172 invalid:
173                 internal(file_line, "cgen_operate: invalid args %02x, %02x, %02x", ra, rb[0], rc);
174         }
175         cgen_four(mc);
176         return true;
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;
184         mc |= rc & 0x1f;
185         mc |= (rb & 0x1f) << 16;
186         cgen_four(mc);
187         return true;
190 static bool attr_w cgen_branch(struct codegen_context *ctx, uint32_t mc, unsigned ra)
192         mc |= ra << 21;
193         g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
194         cgen_four(mc);
195         return true;
198 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
200         uint32_t mc;
201         int64_t imm;
202         uint8_t z = R_ZERO;
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));
211                                 return true;
212                         }
213                         if (!(imm & 0xffff) && imm >= -0x80000000L && imm < 0x80000000L) {
214                                 g(cgen_memory(ctx, ALPHA_LDAH, arg1[0], R_ZERO, imm / 0x10000));
215                                 return true;
216                         }
217                         internal(file_line, "cgen_mov: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
218                 }
219                 if (arg2[0] == ARG_ADDRESS_1) {
220                         imm = get_imm(&arg2[2]);
221                         switch (size) {
222                                 case OP_SIZE_1:
223                                         if (unlikely(!ARCH_HAS_BWX))
224                                                 goto invalid;
225                                         mc = ALPHA_LDBU;
226                                         break;
227                                 case OP_SIZE_2:
228                                         if (unlikely(!ARCH_HAS_BWX))
229                                                 goto invalid;
230                                         mc = ALPHA_LDWU;
231                                         break;
232                                 case OP_SIZE_8:
233                                         mc = ALPHA_LDQ;
234                                         break;
235                                 default:
236                                         goto invalid;
237                         }
238                         g(cgen_memory(ctx, mc, *arg1, arg2[1], imm));
239                         return true;
240                 }
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]));
245                         return true;
246                 }
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]));
250                         return true;
251                 }
252                 goto invalid;
253         }
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]));
258                         return true;
259                 }
260                 if (arg2[0] < 0x40)
261                         goto invalid;
262                 if (arg2[0] == ARG_ADDRESS_1) {
263                         imm = get_imm(&arg2[2]);
264                         switch (size) {
265                                 case OP_SIZE_4: mc = ALPHA_LDS; break;
266                                 case OP_SIZE_8: mc = ALPHA_LDT; break;
267                                 default:        goto invalid;
268                         }
269                         g(cgen_memory(ctx, mc, *arg1 & 0x1f, arg2[1], imm));
270                         return true;
271                 }
272                 goto invalid;
273         }
274         if (arg1[0] == ARG_ADDRESS_1) {
275                 if (arg2[0] == ARG_IMM) {
276                         imm = get_imm(&arg2[1]);
277                         if (unlikely(imm != 0))
278                                 goto invalid;
279                         arg2 = &z;
280                 }
281                 if (arg2[0] < 0x20) {
282                         imm = get_imm(&arg1[2]);
283                         switch (size) {
284                                 case OP_SIZE_1:
285                                         if (unlikely(!ARCH_HAS_BWX))
286                                                 goto invalid;
287                                         mc = ALPHA_STB;
288                                         break;
289                                 case OP_SIZE_2:
290                                         if (unlikely(!ARCH_HAS_BWX))
291                                                 goto invalid;
292                                         mc = ALPHA_STW;
293                                         break;
294                                 case OP_SIZE_4:
295                                         mc = ALPHA_STL;
296                                         break;
297                                 case OP_SIZE_8:
298                                         mc = ALPHA_STQ;
299                                         break;
300                                 default:
301                                         goto invalid;
302                         }
303                         g(cgen_memory(ctx, mc, *arg2, arg1[1], imm));
304                         return true;
305                 }
306                 if (arg2[0] < 0x40) {
307                         imm = get_imm(&arg1[2]);
308                         switch (size) {
309                                 case OP_SIZE_4: mc = ALPHA_STS; break;
310                                 case OP_SIZE_8: mc = ALPHA_STT; break;
311                                 default:        goto invalid;
312                         }
313                         g(cgen_memory(ctx, mc, *arg2 & 0x1f, arg1[1], imm));
314                         return true;
315                 }
316                 goto invalid;
317         }
318 invalid:
319         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
320         return false;
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));
328                 return true;
329         }
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));
336                 return true;
337         }
339         if (unlikely(*arg1 >= 0x20))
340                 goto invalid;
342         if (*arg2 == ARG_ADDRESS_1) {
343                 if (unlikely(size < OP_SIZE_4))
344                         goto invalid;
345                 g(cgen_memory(ctx, ALPHA_LDL, *arg1, arg2[1], get_imm(&arg2[2])));
346                 return true;
347         }
348         if (*arg2 < 0x20) {
349                 uint32_t mc;
350                 switch (size) {
351                         case OP_SIZE_1:
352                                 if (unlikely(!ARCH_HAS_BWX))
353                                         goto invalid;
354                                 mc = ALPHA_SEXTB;
355                                 break;
356                         case OP_SIZE_2:
357                                 if (unlikely(!ARCH_HAS_BWX))
358                                         goto invalid;
359                                 mc = ALPHA_SEXTW;
360                                 break;
361                         case OP_SIZE_4:
362                                 mc = ALPHA_ADDL;
363                                 break;
364                         default:
365                                 goto invalid;
366                 }
367                 g(cgen_operate(ctx, mc, 0x1f, arg2, *arg1));
368                 return true;
369         }
371 invalid:
372         internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, *arg1, *arg2);
373         return false;
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])));
385                 return true;
386         } else if (*arg1 == ARG_ADDRESS_1 && *arg2 < 0x20) {
387                 g(cgen_memory(ctx, ALPHA_STQ_U, *arg2, arg1[1], get_imm(&arg1[2])));
388                 return true;
389         }
391         internal(file_line, "cgen_mov_u: invalid parameters %02x, %02x", *arg1, *arg2);
392         return false;
395 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
397         uint32_t mc;
398         bool swap = false;
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);
403         switch (aux) {
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);
415         }
416         if (swap) {
417                 uint8_t *argx;
418                 if (arg3[0] == ARG_IMM)
419                         internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
420                 argx = arg2;
421                 arg2 = arg3;
422                 arg3 = argx;
423         }
424         g(cgen_operate(ctx, mc, *arg2, arg3, *arg1));
425         return true;
428 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
430         uint32_t mc;
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]);
437                 switch (alu) {
438                         case ALU_SUB:
439                                 imm = -(uint64_t)imm;
440                                 /*-fallthrough*/
441                         case ALU_ADD:
442                                 if (imm >= -0x8000 && imm < 0x8000) {
443                                         g(cgen_memory(ctx, ALPHA_LDA, arg1[0], arg2[0], imm));
444                                         return true;
445                                 }
446                                 if (!(imm & 0xffff) && imm >= -0x80000000L && imm < 0x80000000L) {
447                                         g(cgen_memory(ctx, ALPHA_LDAH, arg1[0], arg2[0], imm / 0x10000));
448                                         return true;
449                                 }
450                                 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
451                 }
452         }
453         switch (alu) {
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);
473         }
474         if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
475                 uint8_t *arg_swp = arg3;
476                 arg3 = arg2;
477                 arg2 = arg_swp;
478         }
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;
492                 else
493                         internal(file_line, "cgen_alu: invalid shifted register operation: %02x, %u", arg2[1], alu);
494                 arg2 += 2;
495         }
496         g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
497         return true;
500 static bool attr_w cgen_alu_trap(struct codegen_context *ctx, unsigned size, unsigned alu)
502         uint32_t mc;
503         uint32_t trap_label;
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);
509         switch (alu) {
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);
514         }
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);
519         return true;
522 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
524         uint32_t mc;
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);
530         if (trap) {
531                 trap_label = cget_four(ctx);
532         }
533         switch (alu) {
534                 case ALU1_NOT:
535                         mc = ALPHA_ORNOT;
536                         g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
537                         break;
538                 case ALU1_NEG:
539                         if (!trap)
540                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
541                         else
542                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
543                         g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
544                         break;
545                 case ALU1_INC:
546                         if (!trap)
547                                 mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL;
548                         else
549                                 mc = size == OP_SIZE_8 ? ALPHA_ADDQ_V : ALPHA_ADDL_V;
550                         g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
551                         break;
552                 case ALU1_DEC:
553                         if (!trap)
554                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
555                         else
556                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
557                         g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
558                         break;
559                 case ALU1_BSF:
560                         mc = ALPHA_CTTZ;
561                         g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
562                         break;
563                 case ALU1_LZCNT:
564                         mc = ALPHA_CTLZ;
565                         g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
566                         break;
567                 case ALU1_POPCNT:
568                         mc = ALPHA_CTPOP;
569                         g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
570                         break;
571                 default:
572                         internal(file_line, "cgen_alu1: invalid alu %u", alu);
573         }
574         if (trap) {
575                 g(cgen_trap(ctx, trap_label));
576                 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
577                         cgen_four(ALPHA_TRAPB);
578         }
579         return true;
582 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned alu)
584         uint32_t mc;
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);
589         switch (alu) {
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);
594         }
595         g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
596         return true;
599 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
601         uint32_t mc;
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);
607         switch (aux) {
608                 case COND_B:
609                 case COND_L:
610                 case COND_S:
611                         mc = ALPHA_CMOVLT; break;
612                 case COND_AE:
613                 case COND_GE:
614                 case COND_NS:
615                         mc = ALPHA_CMOVGE; break;
616                 case COND_E:
617                         mc = ALPHA_CMOVEQ; break;
618                 case COND_NE:
619                         mc = ALPHA_CMOVNE; break;
620                 case COND_BE:
621                 case COND_LE:
622                         mc = ALPHA_CMOVLE; break;
623                 case COND_A:
624                 case COND_G:
625                         mc = ALPHA_CMOVGT; break;
626                 case COND_BLBC:
627                         mc = ALPHA_CMOVLBC; break;
628                 case COND_BLBS:
629                         mc = ALPHA_CMOVLBS; break;
630                 default:
631                         internal(file_line, "cgen_movr: invalid condition %u", aux);
632         }
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]));
636         return true;
639 static bool attr_w cgen_fp_cmp_trap(struct codegen_context *ctx, unsigned aux)
641         uint32_t mc;
642         bool swap = false;
643         uint32_t trap_label;
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);
649         switch (aux) {
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);
656         }
657         if (swap) {
658                 uint8_t *argx;
659                 argx = arg2;
660                 arg2 = arg3;
661                 arg3 = argx;
662         }
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);
667         return true;
670 static bool attr_w cgen_fp_cmp_unordered(struct codegen_context *ctx)
672         uint32_t mc;
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);
681         return true;
684 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
686         uint32_t mc;
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);
691         switch (aux) {
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);
697         }
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);
701         return true;
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);
709         switch (aux) {
710                 case FP_ALU1_NEG:       g(cgen_fp_operate(ctx, ALPHA_CPYSN, arg2[0], arg2[0], arg1[0]));
711                                         break;
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);
715                                         break;
716                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
717         }
718         return true;
721 static bool attr_w cgen_fp_to_int64_trap(struct codegen_context *ctx)
723         uint32_t mc;
724         uint32_t trap_label;
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);
730         mc = ALPHA_CVTTQ_V;
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);
735         return true;
738 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
740         uint32_t mc;
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);
748         return true;
751 static bool attr_w cgen_fp_int64_to_int32_trap(struct codegen_context *ctx)
753         uint32_t mc;
754         uint32_t trap_label;
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);
760         mc = ALPHA_CVTQL_V;
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);
765         return true;
769 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux)
771         uint32_t mc;
772         uint8_t reg = cget_one(ctx);
773         switch (aux) {
774                 case COND_B:
775                 case COND_L:
776                 case COND_S:
777                         mc = ALPHA_BLT; break;
778                 case COND_AE:
779                 case COND_GE:
780                 case COND_NS:
781                         mc = ALPHA_BGE; break;
782                 case COND_E:
783                         mc = ALPHA_BEQ; break;
784                 case COND_NE:
785                         mc = ALPHA_BNE; break;
786                 case COND_BE:
787                 case COND_LE:
788                         mc = ALPHA_BLE; break;
789                 case COND_A:
790                 case COND_G:
791                         mc = ALPHA_BGT; break;
792                 case COND_BLBC:
793                         mc = ALPHA_BLBC; break;
794                 case COND_BLBS:
795                         mc = ALPHA_BLBS; break;
796                 default:
797                         internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
798         }
799         g(cgen_branch(ctx, mc, reg));
800         return true;
803 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
805         uint32_t mc;
806         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2) - 1;
807         switch (reloc->length) {
808                 case JMP_SHORTEST:
809                         if (unlikely(offs < -0x00100000) || unlikely(offs >= 0x00100000))
810                                 return false;
811                         memcpy(&mc, ctx->mcode + reloc->position, 4);
812                         mc &= 0xffe00000U;
813                         mc |= offs & 0x001fffffU;
814                         memcpy(ctx->mcode + reloc->position, &mc, 4);
815                         return true;
816                 default:
817                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
818         }
819         return false;
822 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
824         uint8_t reg;
825         /*debug("insn: %08x", insn);*/
826         if (unlikely(insn_writes_flags(insn)))
827                 goto invalid_insn;
828         switch (insn_opcode(insn)) {
829                 case INSN_ENTRY:
830                         g(cgen_entry(ctx));
831                         return true;
832                 case INSN_LABEL:
833                         g(cgen_label(ctx));
834                         return true;
835                 case INSN_RET:
836                         cgen_four(ALPHA_RETURN);
837                         return true;
838                 case INSN_CALL_INDIRECT:
839                         reg = cget_one(ctx);
840                         if (unlikely(reg != R_T12))
841                                 internal(file_line, "cgen_insn: invalid call register %u", (unsigned)reg);
842                         cgen_four(ALPHA_JSR_T12);
843                         return true;
844                 case INSN_MOV:
845                         g(cgen_mov(ctx, insn_op_size(insn)));
846                         return true;
847                 case INSN_MOVSX:
848                         g(cgen_movsx(ctx, insn_op_size(insn)));
849                         return true;
850                 case INSN_MOV_U:
851                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
852                                 goto invalid_insn;
853                         g(cgen_mov_u(ctx));
854                         return true;
855                 case INSN_CMP_DEST_REG:
856                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
857                                 goto invalid_insn;
858                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
859                         return true;
860                 case INSN_ALU:
861                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
862                                 goto invalid_insn;
863                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
864                         return true;
865                 case INSN_ALU_TRAP:
866                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
867                                 goto invalid_insn;
868                         g(cgen_alu_trap(ctx, insn_op_size(insn), insn_aux(insn)));
869                         return true;
870                 case INSN_ALU1:
871                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
872                                 goto invalid_insn;
873                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
874                         return true;
875                 case INSN_ALU1_TRAP:
876                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
877                                 goto invalid_insn;
878                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
879                         return true;
880                 case INSN_ROT:
881                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
882                                 goto invalid_insn;
883                         g(cgen_rot(ctx, insn_aux(insn)));
884                         return true;
885                 case INSN_MOVR:
886                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
887                                 goto invalid_insn;
888                         g(cgen_movr(ctx, insn_aux(insn)));
889                         return true;
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))
892                                 goto invalid_insn;
893                         g(cgen_fp_cmp_trap(ctx, insn_aux(insn)));
894                         return true;
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))
897                                 goto invalid_insn;
898                         g(cgen_fp_cmp_unordered(ctx));
899                         return true;
900                 case INSN_FP_ALU:
901                         if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
902                                 goto invalid_insn;
903                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
904                         return true;
905                 case INSN_FP_ALU1:
906                         if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
907                                 goto invalid_insn;
908                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
909                         return true;
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))
912                                 goto invalid_insn;
913                         g(cgen_fp_to_int64_trap(ctx));
914                         return true;
915                 case INSN_FP_FROM_INT64:
916                         if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
917                                 goto invalid_insn;
918                         g(cgen_fp_from_int(ctx, insn_op_size(insn)));
919                         return true;
920                 case INSN_FP_INT64_TO_INT32_TRAP:
921                         g(cgen_fp_int64_to_int32_trap(ctx));
922                         return true;
923                 case INSN_JMP:
924                         g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
925                         cgen_four(ALPHA_BR);
926                         return true;
927                 case INSN_JMP_REG:
928                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
929                                 goto invalid_insn;
930                         g(cgen_jmp_reg(ctx, insn_aux(insn)));
931                         return true;
932                 case INSN_JMP_INDIRECT:
933                         reg = cget_one(ctx);
934                         cgen_four(ALPHA_JMP + ((uint32_t)reg << 16));
935                         return true;
936                 case INSN_MB:
937                         cgen_four(ALPHA_MB);
938                         return true;
939                 default:
940                 invalid_insn:
941                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
942                         return false;
943         }