x86: implement 128-bit popcnt
[ajla.git] / c2-alpha.inc
blobedcc18fec51a039efa39ed18ce2d8853d65a2a2f
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 (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]));
250                         return true;
251                 }
252                 goto invalid;
253         }
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]));
258                         return true;
259                 }
260                 if (reg_is_fp(arg2[0])) {
261                         g(cgen_fp_operate(ctx, ALPHA_CPYS, arg2[0], arg2[0], arg1[0]));
262                         return true;
263                 }
264                 if (arg2[0] == ARG_ADDRESS_1) {
265                         imm = get_imm(&arg2[2]);
266                         switch (size) {
267                                 case OP_SIZE_4: mc = ALPHA_LDS; break;
268                                 case OP_SIZE_8: mc = ALPHA_LDT; break;
269                                 default:        goto invalid;
270                         }
271                         g(cgen_memory(ctx, mc, *arg1 & 0x1f, arg2[1], imm));
272                         return true;
273                 }
274                 goto invalid;
275         }
276         if (arg1[0] == ARG_ADDRESS_1) {
277                 if (arg2[0] == ARG_IMM) {
278                         imm = get_imm(&arg2[1]);
279                         if (unlikely(imm != 0))
280                                 goto invalid;
281                         arg2 = &z;
282                 }
283                 if (arg2[0] < 0x20) {
284                         imm = get_imm(&arg1[2]);
285                         switch (size) {
286                                 case OP_SIZE_1:
287                                         if (unlikely(!ARCH_HAS_BWX))
288                                                 goto invalid;
289                                         mc = ALPHA_STB;
290                                         break;
291                                 case OP_SIZE_2:
292                                         if (unlikely(!ARCH_HAS_BWX))
293                                                 goto invalid;
294                                         mc = ALPHA_STW;
295                                         break;
296                                 case OP_SIZE_4:
297                                         mc = ALPHA_STL;
298                                         break;
299                                 case OP_SIZE_8:
300                                         mc = ALPHA_STQ;
301                                         break;
302                                 default:
303                                         goto invalid;
304                         }
305                         g(cgen_memory(ctx, mc, *arg2, arg1[1], imm));
306                         return true;
307                 }
308                 if (reg_is_fp(arg2[0])) {
309                         imm = get_imm(&arg1[2]);
310                         switch (size) {
311                                 case OP_SIZE_4: mc = ALPHA_STS; break;
312                                 case OP_SIZE_8: mc = ALPHA_STT; break;
313                                 default:        goto invalid;
314                         }
315                         g(cgen_memory(ctx, mc, *arg2 & 0x1f, arg1[1], imm));
316                         return true;
317                 }
318                 goto invalid;
319         }
320 invalid:
321         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
322         return false;
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));
330                 return true;
331         }
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));
338                 return true;
339         }
341         if (unlikely(*arg1 >= 0x20))
342                 goto invalid;
344         if (*arg2 == ARG_ADDRESS_1) {
345                 if (unlikely(size < OP_SIZE_4))
346                         goto invalid;
347                 g(cgen_memory(ctx, ALPHA_LDL, *arg1, arg2[1], get_imm(&arg2[2])));
348                 return true;
349         }
350         if (*arg2 < 0x20) {
351                 uint32_t mc;
352                 switch (size) {
353                         case OP_SIZE_1:
354                                 if (unlikely(!ARCH_HAS_BWX))
355                                         goto invalid;
356                                 mc = ALPHA_SEXTB;
357                                 break;
358                         case OP_SIZE_2:
359                                 if (unlikely(!ARCH_HAS_BWX))
360                                         goto invalid;
361                                 mc = ALPHA_SEXTW;
362                                 break;
363                         case OP_SIZE_4:
364                                 mc = ALPHA_ADDL;
365                                 break;
366                         default:
367                                 goto invalid;
368                 }
369                 g(cgen_operate(ctx, mc, 0x1f, arg2, *arg1));
370                 return true;
371         }
373 invalid:
374         internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, *arg1, *arg2);
375         return false;
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])));
387                 return true;
388         } else if (*arg1 == ARG_ADDRESS_1 && *arg2 < 0x20) {
389                 g(cgen_memory(ctx, ALPHA_STQ_U, *arg2, arg1[1], get_imm(&arg1[2])));
390                 return true;
391         }
393         internal(file_line, "cgen_mov_u: invalid parameters %02x, %02x", *arg1, *arg2);
394         return false;
397 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
399         uint32_t mc;
400         bool swap = false;
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);
405         switch (aux) {
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);
417         }
418         if (swap) {
419                 uint8_t *argx;
420                 if (arg3[0] == ARG_IMM)
421                         internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
422                 argx = arg2;
423                 arg2 = arg3;
424                 arg3 = argx;
425         }
426         g(cgen_operate(ctx, mc, *arg2, arg3, *arg1));
427         return true;
430 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
432         uint32_t mc;
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]);
439                 switch (alu) {
440                         case ALU_SUB:
441                                 imm = -(uint64_t)imm;
442                                 /*-fallthrough*/
443                         case ALU_ADD:
444                                 if (imm >= -0x8000 && imm < 0x8000) {
445                                         g(cgen_memory(ctx, ALPHA_LDA, arg1[0], arg2[0], imm));
446                                         return true;
447                                 }
448                                 if (!(imm & 0xffff) && imm >= -0x80000000L && imm < 0x80000000L) {
449                                         g(cgen_memory(ctx, ALPHA_LDAH, arg1[0], arg2[0], imm / 0x10000));
450                                         return true;
451                                 }
452                                 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
453                 }
454         }
455         switch (alu) {
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);
475         }
476         if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
477                 uint8_t *arg_swp = arg3;
478                 arg3 = arg2;
479                 arg2 = arg_swp;
480         }
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;
494                 else
495                         internal(file_line, "cgen_alu: invalid shifted register operation: %02x, %u", arg2[1], alu);
496                 arg2 += 2;
497         }
498         g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
499         return true;
502 static bool attr_w cgen_alu_trap(struct codegen_context *ctx, unsigned size, unsigned alu)
504         uint32_t mc;
505         uint32_t trap_label;
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);
511         switch (alu) {
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);
516         }
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);
521         return true;
524 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
526         uint32_t mc;
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);
532         if (trap) {
533                 trap_label = cget_four(ctx);
534         }
535         switch (alu) {
536                 case ALU1_NOT:
537                         mc = ALPHA_ORNOT;
538                         g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
539                         break;
540                 case ALU1_NEG:
541                         if (!trap)
542                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
543                         else
544                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
545                         g(cgen_operate(ctx, mc, R_ZERO, arg2, arg1[0]));
546                         break;
547                 case ALU1_INC:
548                         if (!trap)
549                                 mc = size == OP_SIZE_8 ? ALPHA_ADDQ : ALPHA_ADDL;
550                         else
551                                 mc = size == OP_SIZE_8 ? ALPHA_ADDQ_V : ALPHA_ADDL_V;
552                         g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
553                         break;
554                 case ALU1_DEC:
555                         if (!trap)
556                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ : ALPHA_SUBL;
557                         else
558                                 mc = size == OP_SIZE_8 ? ALPHA_SUBQ_V : ALPHA_SUBL_V;
559                         g(cgen_operate(ctx, mc, arg2[0], one_imm, arg1[0]));
560                         break;
561                 case ALU1_BSF:
562                         mc = ALPHA_CTTZ;
563                         g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
564                         break;
565                 case ALU1_LZCNT:
566                         mc = ALPHA_CTLZ;
567                         g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
568                         break;
569                 case ALU1_POPCNT:
570                         mc = ALPHA_CTPOP;
571                         g(cgen_operate(ctx, mc, 0x1f, arg2, arg1[0]));
572                         break;
573                 default:
574                         internal(file_line, "cgen_alu1: invalid alu %u", alu);
575         }
576         if (trap) {
577                 g(cgen_trap(ctx, trap_label));
578                 if (!cpu_test_feature(CPU_FEATURE_precise_trap))
579                         cgen_four(ALPHA_TRAPB);
580         }
581         return true;
584 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned alu)
586         uint32_t mc;
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);
591         switch (alu) {
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);
596         }
597         g(cgen_operate(ctx, mc, arg2[0], arg3, arg1[0]));
598         return true;
601 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
603         uint32_t mc;
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);
609         switch (aux) {
610                 case COND_B:
611                 case COND_L:
612                 case COND_S:
613                         mc = ALPHA_CMOVLT; break;
614                 case COND_AE:
615                 case COND_GE:
616                 case COND_NS:
617                         mc = ALPHA_CMOVGE; break;
618                 case COND_E:
619                         mc = ALPHA_CMOVEQ; break;
620                 case COND_NE:
621                         mc = ALPHA_CMOVNE; break;
622                 case COND_BE:
623                 case COND_LE:
624                         mc = ALPHA_CMOVLE; break;
625                 case COND_A:
626                 case COND_G:
627                         mc = ALPHA_CMOVGT; break;
628                 case COND_BLBC:
629                         mc = ALPHA_CMOVLBC; break;
630                 case COND_BLBS:
631                         mc = ALPHA_CMOVLBS; break;
632                 default:
633                         internal(file_line, "cgen_movr: invalid condition %u", aux);
634         }
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]));
638         return true;
641 static bool attr_w cgen_fp_cmp_trap(struct codegen_context *ctx, unsigned aux)
643         uint32_t mc;
644         bool swap = false;
645         uint32_t trap_label;
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);
651         switch (aux) {
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);
658         }
659         if (swap) {
660                 uint8_t *argx;
661                 argx = arg2;
662                 arg2 = arg3;
663                 arg3 = argx;
664         }
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);
669         return true;
672 static bool attr_w cgen_fp_cmp_unordered(struct codegen_context *ctx)
674         uint32_t mc;
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);
683         return true;
686 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
688         uint32_t mc;
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);
693         switch (aux) {
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);
699         }
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);
703         return true;
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);
711         switch (aux) {
712                 case FP_ALU1_NEG:       g(cgen_fp_operate(ctx, ALPHA_CPYSN, arg2[0], arg2[0], arg1[0]));
713                                         break;
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);
717                                         break;
718                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
719         }
720         return true;
723 static bool attr_w cgen_fp_to_int64_trap(struct codegen_context *ctx)
725         uint32_t mc;
726         uint32_t trap_label;
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);
732         mc = ALPHA_CVTTQ_V;
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);
737         return true;
740 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
742         uint32_t mc;
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);
750         return true;
753 static bool attr_w cgen_fp_int64_to_int32_trap(struct codegen_context *ctx)
755         uint32_t mc;
756         uint32_t trap_label;
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);
762         mc = ALPHA_CVTQL_V;
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);
767         return true;
771 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux)
773         uint32_t mc;
774         uint8_t reg = cget_one(ctx);
775         switch (aux) {
776                 case COND_B:
777                 case COND_L:
778                 case COND_S:
779                         mc = ALPHA_BLT; break;
780                 case COND_AE:
781                 case COND_GE:
782                 case COND_NS:
783                         mc = ALPHA_BGE; break;
784                 case COND_E:
785                         mc = ALPHA_BEQ; break;
786                 case COND_NE:
787                         mc = ALPHA_BNE; break;
788                 case COND_BE:
789                 case COND_LE:
790                         mc = ALPHA_BLE; break;
791                 case COND_A:
792                 case COND_G:
793                         mc = ALPHA_BGT; break;
794                 case COND_BLBC:
795                         mc = ALPHA_BLBC; break;
796                 case COND_BLBS:
797                         mc = ALPHA_BLBS; break;
798                 default:
799                         internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
800         }
801         g(cgen_branch(ctx, mc, reg));
802         return true;
805 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
807         uint32_t mc;
808         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2) - 1;
809         switch (reloc->length) {
810                 case JMP_SHORTEST:
811                         if (unlikely(offs < -0x00100000) || unlikely(offs >= 0x00100000))
812                                 return false;
813                         memcpy(&mc, ctx->mcode + reloc->position, 4);
814                         mc &= 0xffe00000U;
815                         mc |= offs & 0x001fffffU;
816                         memcpy(ctx->mcode + reloc->position, &mc, 4);
817                         return true;
818                 default:
819                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
820         }
821         return false;
824 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
826         uint8_t reg;
827         /*debug("insn: %08x", insn);*/
828         if (unlikely(insn_writes_flags(insn)))
829                 goto invalid_insn;
830         switch (insn_opcode(insn)) {
831                 case INSN_ENTRY:
832                         g(cgen_entry(ctx));
833                         return true;
834                 case INSN_LABEL:
835                         g(cgen_label(ctx));
836                         return true;
837                 case INSN_RET:
838                         cgen_four(ALPHA_RETURN);
839                         return true;
840                 case INSN_CALL_INDIRECT:
841                         reg = cget_one(ctx);
842                         if (unlikely(reg != R_T12))
843                                 internal(file_line, "cgen_insn: invalid call register %u", (unsigned)reg);
844                         cgen_four(ALPHA_JSR_T12);
845                         return true;
846                 case INSN_MOV:
847                         g(cgen_mov(ctx, insn_op_size(insn)));
848                         return true;
849                 case INSN_MOVSX:
850                         g(cgen_movsx(ctx, insn_op_size(insn)));
851                         return true;
852                 case INSN_MOV_U:
853                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
854                                 goto invalid_insn;
855                         g(cgen_mov_u(ctx));
856                         return true;
857                 case INSN_CMP_DEST_REG:
858                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
859                                 goto invalid_insn;
860                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
861                         return true;
862                 case INSN_ALU:
863                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
864                                 goto invalid_insn;
865                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
866                         return true;
867                 case INSN_ALU_TRAP:
868                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
869                                 goto invalid_insn;
870                         g(cgen_alu_trap(ctx, insn_op_size(insn), insn_aux(insn)));
871                         return true;
872                 case INSN_ALU1:
873                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
874                                 goto invalid_insn;
875                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
876                         return true;
877                 case INSN_ALU1_TRAP:
878                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
879                                 goto invalid_insn;
880                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
881                         return true;
882                 case INSN_ROT:
883                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
884                                 goto invalid_insn;
885                         g(cgen_rot(ctx, insn_aux(insn)));
886                         return true;
887                 case INSN_MOVR:
888                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
889                                 goto invalid_insn;
890                         g(cgen_movr(ctx, insn_aux(insn)));
891                         return true;
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))
894                                 goto invalid_insn;
895                         g(cgen_fp_cmp_trap(ctx, insn_aux(insn)));
896                         return true;
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))
899                                 goto invalid_insn;
900                         g(cgen_fp_cmp_unordered(ctx));
901                         return true;
902                 case INSN_FP_ALU:
903                         if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
904                                 goto invalid_insn;
905                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
906                         return true;
907                 case INSN_FP_ALU1:
908                         if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
909                                 goto invalid_insn;
910                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
911                         return true;
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))
914                                 goto invalid_insn;
915                         g(cgen_fp_to_int64_trap(ctx));
916                         return true;
917                 case INSN_FP_FROM_INT64:
918                         if (unlikely(insn_op_size(insn) != OP_SIZE_4) && unlikely(insn_op_size(insn) != OP_SIZE_8))
919                                 goto invalid_insn;
920                         g(cgen_fp_from_int(ctx, insn_op_size(insn)));
921                         return true;
922                 case INSN_FP_INT64_TO_INT32_TRAP:
923                         g(cgen_fp_int64_to_int32_trap(ctx));
924                         return true;
925                 case INSN_JMP:
926                         g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
927                         cgen_four(ALPHA_BR);
928                         return true;
929                 case INSN_JMP_REG:
930                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
931                                 goto invalid_insn;
932                         g(cgen_jmp_reg(ctx, insn_aux(insn)));
933                         return true;
934                 case INSN_JMP_INDIRECT:
935                         reg = cget_one(ctx);
936                         cgen_four(ALPHA_JMP + ((uint32_t)reg << 16));
937                         return true;
938                 case INSN_MB:
939                         cgen_four(ALPHA_MB);
940                         return true;
941                 default:
942                 invalid_insn:
943                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
944                         return false;
945         }