codegen: introduce cg-spill.inc
[ajla.git] / c2-loong.inc
blob8b9448e9bbfb1ba7f98971b864f6e32d8d1cf96f
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 LOONG_CLO_W             0x00001000U
20 #define LOONG_CLZ_W             0x00001400U
21 #define LOONG_CTO_W             0x00001800U
22 #define LOONG_CTZ_W             0x00001c00U
23 #define LOONG_CLO_D             0x00002000U
24 #define LOONG_CLZ_D             0x00002400U
25 #define LOONG_CTO_D             0x00002800U
26 #define LOONG_CTZ_D             0x00002c00U
27 #define LOONG_REVB_2H           0x00003000U
28 #define LOONG_REVB_4H           0x00003400U
29 #define LOONG_REVB_2W           0x00003800U
30 #define LOONG_REVB_D            0x00003c00U
31 #define LOONG_REVH_2W           0x00004000U
32 #define LOONG_REVH_D            0x00004400U
33 #define LOONG_BITREV_W          0x00005000U
34 #define LOONG_BITREV_D          0x00005400U
35 #define LOONG_EXT_W_H           0x00005800U
36 #define LOONG_EXT_W_B           0x00005c00U
37 #define LOONG_ADD_W             0x00100000U
38 #define LOONG_ADD_D             0x00108000U
39 #define LOONG_SUB_W             0x00110000U
40 #define LOONG_SUB_D             0x00118000U
41 #define LOONG_SLT               0x00120000U
42 #define LOONG_SLTU              0x00128000U
43 #define LOONG_NOR               0x00140000U
44 #define LOONG_AND               0x00148000U
45 #define LOONG_OR                0x00150000U
46 #define LOONG_XOR               0x00158000U
47 #define LOONG_ORN               0x00160000U
48 #define LOONG_ANDN              0x00168000U
49 #define LOONG_SLL_W             0x00170000U
50 #define LOONG_SRL_W             0x00178000U
51 #define LOONG_SRA_W             0x00180000U
52 #define LOONG_SLL_D             0x00188000U
53 #define LOONG_SRL_D             0x00190000U
54 #define LOONG_SRA_D             0x00198000U
55 #define LOONG_ROTR_W            0x001b0000U
56 #define LOONG_ROTR_D            0x001b8000U
57 #define LOONG_MUL_W             0x001c0000U
58 #define LOONG_MULH_W            0x001c8000U
59 #define LOONG_MULH_WU           0x001d0000U
60 #define LOONG_MUL_D             0x001d8000U
61 #define LOONG_MULH_D            0x001e0000U
62 #define LOONG_MULH_DU           0x001e8000U
63 #define LOONG_DIV_W             0x00200000U
64 #define LOONG_MOD_W             0x00208000U
65 #define LOONG_DIV_WU            0x00210000U
66 #define LOONG_MOD_WU            0x00218000U
67 #define LOONG_DIV_D             0x00220000U
68 #define LOONG_MOD_D             0x00228000U
69 #define LOONG_DIV_DU            0x00230000U
70 #define LOONG_MOD_DU            0x00238000U
71 #define LOONG_SLLI_W            0x00408000U
72 #define LOONG_SLLI_D            0x00410000U
73 #define LOONG_SRLI_W            0x00448000U
74 #define LOONG_SRLI_D            0x00450000U
75 #define LOONG_SRAI_W            0x00488000U
76 #define LOONG_SRAI_D            0x00490000U
77 #define LOONG_ROTRI_W           0x004c8000U
78 #define LOONG_ROTRI_D           0x004d0000U
79 #define LOONG_BSTRINS_W         0x00600000U
80 #define LOONG_BSTRPICK_W        0x00608000U
81 #define LOONG_BSTRINS_D         0x00800000U
82 #define LOONG_BSTRPICK_D        0x00c00000U
83 #define LOONG_FADD_S            0x01008000U
84 #define LOONG_FADD_D            0x01010000U
85 #define LOONG_FSUB_S            0x01028000U
86 #define LOONG_FSUB_D            0x01030000U
87 #define LOONG_FMUL_S            0x01048000U
88 #define LOONG_FMUL_D            0x01050000U
89 #define LOONG_FDIV_S            0x01068000U
90 #define LOONG_FDIV_D            0x01070000U
91 #define LOONG_FNEG_S            0x01141400U
92 #define LOONG_FNEG_D            0x01141800U
93 #define LOONG_FSQRT_S           0x01144400U
94 #define LOONG_FSQRT_D           0x01144800U
95 #define LOONG_FMOV_S            0x01149400U
96 #define LOONG_FMOV_D            0x01149800U
97 #define LOONG_MOVFR2GR_S        0x0114b400U
98 #define LOONG_MOVFR2GR_D        0x0114b800U
99 #define LOONG_MOVCF2GR          0x0114dc00U
100 #define LOONG_FTINTRZ_W_S       0x011a8400U
101 #define LOONG_FTINTRZ_W_D       0x011a8800U
102 #define LOONG_FTINTRZ_L_S       0x011aa400U
103 #define LOONG_FTINTRZ_L_D       0x011aa800U
104 #define LOONG_FFINT_S_W         0x011d1000U
105 #define LOONG_FFINT_S_L         0x011d1800U
106 #define LOONG_FFINT_D_W         0x011d2000U
107 #define LOONG_FFINT_D_L         0x011d2800U
108 #define LOONG_FRINT_S           0x011e4400U
109 #define LOONG_FRINT_D           0x011e4800U
110 #define LOONG_SLTI              0x02000000U
111 #define LOONG_SLTUI             0x02400000U
112 #define LOONG_ADDI_W            0x02800000U
113 #define LOONG_ADDI_D            0x02c00000U
114 #define LOONG_LU52I_D           0x03000000U
115 #define LOONG_ANDI              0x03400000U
116 #define LOONG_ORI               0x03800000U
117 #define LOONG_XORI              0x03c00000U
118 #define LOONG_FCMP_S            0x0c100000U
119 #define LOONG_FCMP_D            0x0c200000U
120 #define  LOONG_FCMP_SIG                 0x00008000U
121 #define  LOONG_FCMP_AF                  0x00000000U
122 #define  LOONG_FCMP_LT                  0x00010000U
123 #define  LOONG_FCMP_EQ                  0x00020000U
124 #define  LOONG_FCMP_LE                  0x00030000U
125 #define  LOONG_FCMP_UN                  0x00040000U
126 #define  LOONG_FCMP_ULT                 0x00050000U
127 #define  LOONG_FCMP_UEQ                 0x00060000U
128 #define  LOONG_FCMP_ULE                 0x00070000U
129 #define  LOONG_FCMP_NE                  0x00080000U
130 #define  LOONG_FCMP_OR                  0x000a0000U
131 #define  LOONG_FCMP_UNE                 0x000c0000U
132 #define LOONG_MOVGR2FR_W        0x0114a400U
133 #define LOONG_MOVGR2FR_D        0x0114a800U
134 #define LOONG_LU12I_W           0x14000000U
135 #define LOONG_LU32I_D           0x16000000U
136 #define LOONG_LDPTR_W           0x24000000U
137 #define LOONG_LDPTR_D           0x26000000U
138 #define LOONG_STPTR_W           0x25000000U
139 #define LOONG_STPTR_D           0x27000000U
140 #define LOONG_LD_B              0x28000000U
141 #define LOONG_LD_H              0x28400000U
142 #define LOONG_LD_W              0x28800000U
143 #define LOONG_LD_D              0x28c00000U
144 #define LOONG_ST_B              0x29000000U
145 #define LOONG_ST_H              0x29400000U
146 #define LOONG_ST_W              0x29800000U
147 #define LOONG_ST_D              0x29c00000U
148 #define LOONG_LD_BU             0x2a000000U
149 #define LOONG_LD_HU             0x2a400000U
150 #define LOONG_LD_WU             0x2a800000U
151 #define LOONG_FLD_S             0x2b000000U
152 #define LOONG_FST_S             0x2b400000U
153 #define LOONG_FLD_D             0x2b800000U
154 #define LOONG_FST_D             0x2bc00000U
155 #define LOONG_LDX_B             0x38000000U
156 #define LOONG_LDX_H             0x38040000U
157 #define LOONG_LDX_W             0x38080000U
158 #define LOONG_LDX_D             0x380c0000U
159 #define LOONG_STX_B             0x38100000U
160 #define LOONG_STX_H             0x38140000U
161 #define LOONG_STX_W             0x38180000U
162 #define LOONG_STX_D             0x381c0000U
163 #define LOONG_LDX_BU            0x38200000U
164 #define LOONG_LDX_HU            0x38240000U
165 #define LOONG_LDX_WU            0x38280000U
166 #define LOONG_FLDX_S            0x38300000U
167 #define LOONG_FLDX_D            0x38340000U
168 #define LOONG_FSTX_S            0x38380000U
169 #define LOONG_FSTX_D            0x383c0000U
170 #define LOONG_BEQZ              0x40000000U
171 #define LOONG_BNEZ              0x44000000U
172 #define LOONG_BCEQZ             0x48000000U
173 #define LOONG_BCNEZ             0x48000100U
174 #define LOONG_JIRL              0x4c000000U
175 #define LOONG_B                 0x50000000U
176 #define LOONG_BEQ               0x58000000U
177 #define LOONG_BNE               0x5c000000U
178 #define LOONG_BLT               0x60000000U
179 #define LOONG_BGE               0x64000000U
180 #define LOONG_BLTU              0x68000000U
181 #define LOONG_BGEU              0x6c000000U
184 #define cgen_i26(opcode, imm)                   cgen_four((opcode) | ((imm) & 0xffffU) << 10 | ((imm) & 0x3ff0000) >> 16)
185 #define cgen_1ri20(opcode, rd, imm)             cgen_four((opcode) | (rd) | ((imm) & 0xFFFFFU) << 5)
186 #define cgen_1ri21(opcode, rj, imm)             cgen_four((opcode) | (rj) << 5 | ((imm) & 0xFFFFU) << 5 | ((imm) & 0x1f0000) >> 16)
187 #define cgen_2r(opcode, rd, rj)                 cgen_four((opcode) | (rd) | (rj) << 5)
188 #define cgen_2ri8(opcode, rd, rj, imm)          cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xffU) << 10)
189 #define cgen_2ri12(opcode, rd, rj, imm)         cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xfffU) << 10)
190 #define cgen_2ri14(opcode, rd, rj, imm)         cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0x3fffU) << 10)
191 #define cgen_2ri16(opcode, rd, rj, imm)         cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xffffU) << 10)
192 #define cgen_2r2i(opcode, rd, rj, imm_m, imm_l) cgen_four((opcode) | (rd) | (rj) << 5 | (imm_m) << 16 | (imm_l) << 10)
193 #define cgen_3r(opcode, rd, rj, rk)             cgen_four((opcode) | (rd) | (rj) << 5 | ((rk) << 10))
195 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, bool call)
197         uint8_t reg = cget_one(ctx);
198         uint8_t save = call ? R_RA : R_ZERO;
199         cgen_2ri16(LOONG_JIRL, save, reg, 0);
200         return true;
203 static const uint32_t st[10] =          { LOONG_ST_B, LOONG_ST_H, LOONG_ST_W, LOONG_ST_D, LOONG_STX_B, LOONG_STX_H, LOONG_STX_W, LOONG_STX_D, LOONG_STPTR_W, LOONG_STPTR_D };
204 static const uint32_t ld_signed[10] =   { LOONG_LD_B, LOONG_LD_H, LOONG_LD_W, LOONG_LD_D, LOONG_LDX_B, LOONG_LDX_H, LOONG_LDX_W, LOONG_LDX_D, LOONG_LDPTR_W, LOONG_LDPTR_D };
205 static const uint32_t ld_unsigned[10] = { LOONG_LD_BU, LOONG_LD_HU, LOONG_LD_WU, LOONG_LD_D, LOONG_LDX_BU, LOONG_LDX_HU, LOONG_LDX_WU, LOONG_LDX_D, -1U, LOONG_LDPTR_D };
206 static const uint32_t st_fp[10] =       { -1U, -1U, LOONG_FST_S, LOONG_FST_D, -1U, -1U, LOONG_FSTX_S, LOONG_FSTX_D, -1U, -1U };
207 static const uint32_t ld_fp[10] =       { -1U, -1U, LOONG_FLD_S, LOONG_FLD_D, -1U, -1U, LOONG_FLDX_S, LOONG_FLDX_D, -1U, -1U };
209 static bool cgen_ld_st(struct codegen_context *ctx, const uint32_t table[10], unsigned size, uint8_t reg, uint8_t *address)
211         int64_t imm;
212         if (address[0] == ARG_ADDRESS_1) {
213                 imm = get_imm(&address[2]);
214                 if (!(imm & 3) && imm >= -0x8000 && imm < 0x8000 && (size == OP_SIZE_4 || size == OP_SIZE_8)) {
215                         uint32_t mc = table[8 + size - OP_SIZE_4];
216                         if (mc != -1U) {
217                                 cgen_2ri14(mc, reg, address[1], (uint64_t)imm >> 2);
218                                 return true;
219                         }
220                 }
221                 if (imm >= -0x800 && imm < 0x800) {
222                         cgen_2ri12(table[size], reg, address[1], imm);
223                         return true;
224                 }
225         } else if (address[0] == ARG_ADDRESS_2) {
226                 imm = get_imm(&address[3]);
227                 if (unlikely(imm != 0))
228                         goto invalid;
229                 cgen_3r(table[4 + size], reg, address[1], address[2]);
230                 return true;
231         }
232 invalid:
233         internal(file_line, "cgen_ld_st: invalid arguments %02x, %02x", reg, address[0]);
234         return false;
237 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
239         int64_t imm;
240         uint8_t *arg1 = ctx->code_position;
241         uint8_t *arg2 = arg1 + arg_size(*arg1);
242         ctx->code_position = arg2 + arg_size(*arg2);
243         if (size == OP_SIZE_NATIVE)
244                 sx = false;
245         if (arg1[0] < 0x20) {
246                 if (arg2[0] < 0x20) {
247                         if (sx) {
248                                 switch (size) {
249                                         case OP_SIZE_1:
250                                                 cgen_2r(LOONG_EXT_W_B, arg1[0], arg2[0]);
251                                                 return true;
252                                         case OP_SIZE_2:
253                                                 cgen_2r(LOONG_EXT_W_H, arg1[0], arg2[0]);
254                                                 return true;
255                                         case OP_SIZE_4:
256                                                 cgen_2ri8(LOONG_SLLI_W, arg1[0], arg2[0], 0);
257                                                 return true;
258                                         default:
259                                                 goto invalid;
260                                 }
261                         } else {
262                                 switch (size) {
263                                         case OP_SIZE_1:
264                                                 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x07, 0x00);
265                                                 return true;
266                                         case OP_SIZE_2:
267                                                 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x0f, 0x00);
268                                                 return true;
269                                         case OP_SIZE_4:
270                                                 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x1f, 0x00);
271                                                 return true;
272                                         case OP_SIZE_8:
273                                                 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
274                                                 return true;
275                                         default:
276                                                 goto invalid;
277                                 }
278                         }
279                 }
280                 if (reg_is_fp(arg2[0])) {
281                         switch (size) {
282                                 case OP_SIZE_4:
283                                         cgen_2r(LOONG_MOVFR2GR_S, arg1[0], arg2[0] & 0x1f);
284                                         return true;
285                                 case OP_SIZE_8:
286                                         cgen_2r(LOONG_MOVFR2GR_D, arg1[0], arg2[0] & 0x1f);
287                                         return true;
288                                 default:
289                                         goto invalid;
290                         }
291                 }
292                 if (arg2[0] == ARG_IMM) {
293                         imm = get_imm(&arg2[1]);
294                         if (imm >= 0 && imm < 0x1000) {
295                                 cgen_2ri12(LOONG_ORI, arg1[0], R_ZERO, imm);
296                                 return true;
297                         }
298                         if (imm >= -0x800 && imm < 0x800) {
299                                 cgen_2ri12(LOONG_ADDI_D, arg1[0], R_ZERO, imm);
300                                 return true;
301                         }
302                         if (!(imm & 0xfff) && imm == (int32_t)imm) {
303                                 cgen_1ri20(LOONG_LU12I_W, arg1[0], (uint64_t)imm >> 12);
304                                 return true;
305                         }
306                         if (!(imm & 0x000fffffffffffffLL)) {
307                                 cgen_2ri12(LOONG_LU52I_D, arg1[0], R_ZERO, (uint64_t)imm >> 52);
308                                 return true;
309                         }
310                         goto invalid;
311                 }
312                 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
313                         if (!sx)
314                                 return cgen_ld_st(ctx, ld_unsigned, size, arg1[0], arg2);
315                         else
316                                 return cgen_ld_st(ctx, ld_signed, size, arg1[0], arg2);
317                 }
318                 goto invalid;
319         }
321         if (reg_is_fp(arg1[0])) {
322                 if (arg2[0] < 0x20) {
323                         switch (size) {
324                                 case OP_SIZE_4:
325                                         cgen_2r(LOONG_MOVGR2FR_W, arg1[0] & 0x1f, arg2[0]);
326                                         return true;
327                                 case OP_SIZE_8:
328                                         cgen_2r(LOONG_MOVGR2FR_D, arg1[0] & 0x1f, arg2[0]);
329                                         return true;
330                                 default:
331                                         goto invalid;
332                         }
333                 }
334                 if (reg_is_fp(arg2[0])) {
335                         switch (size) {
336                                 case OP_SIZE_4:
337                                         cgen_2r(LOONG_FMOV_S, arg1[0] & 0x1f, arg2[0] & 0x1f);
338                                         return true;
339                                 case OP_SIZE_8:
340                                         cgen_2r(LOONG_FMOV_D, arg1[0] & 0x1f, arg2[0] & 0x1f);
341                                         return true;
342                                 default:
343                                         goto invalid;
344                         }
345                 }
346                 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
347                         return cgen_ld_st(ctx, ld_fp, size, arg1[0] & 0x1f, arg2);
348                 }
349         }
351         if (arg1[0] == ARG_ADDRESS_1 || arg1[0] == ARG_ADDRESS_2) {
352                 if (arg2[0] < 0x20) {
353                         return cgen_ld_st(ctx, st, size, arg2[0], arg1);
354                 }
355                 if (reg_is_fp(arg2[0])) {
356                         return cgen_ld_st(ctx, st_fp, size, arg2[0] & 0x1f, arg1);
357                 }
358                 if (arg2[0] == ARG_IMM) {
359                         imm = get_imm(&arg2[1]);
360                         if (unlikely(imm != 0))
361                                 goto invalid;
362                         return cgen_ld_st(ctx, st, size, R_ZERO, arg1);
363                 }
364         }
366 invalid:
367         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
368         return false;
371 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
373         uint32_t mc;
374         bool swap = false;
375         uint8_t z = R_ZERO;
376         uint8_t *arg1 = ctx->code_position;
377         uint8_t *arg2 = arg1 + arg_size(*arg1);
378         uint8_t *arg3 = arg2 + arg_size(*arg2);
379         ctx->code_position = arg3 + arg_size(*arg3);
380         if (arg3[0] == ARG_IMM) {
381                 int64_t imm = get_imm(&arg3[1]);
382                 if (unlikely(imm < -0x800) && unlikely(imm >= 0x800))
383                         internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
384                 switch (aux) {
385                         case COND_B:    mc = LOONG_SLTUI; break;
386                         case COND_L:    mc = LOONG_SLTI; break;
387                         default:        internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
388                 }
389                 cgen_2ri12(mc, arg1[0], arg2[0], imm);
390                 return true;
391         }
392         if (arg2[0] == ARG_IMM) {
393                 int64_t imm = get_imm(&arg2[1]);
394                 if (unlikely(imm != 0))
395                         internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
396                 arg2 = &z;
397         }
398         switch (aux) {
399                 case COND_B:    mc = LOONG_SLTU; break;
400                 case COND_A:    mc = LOONG_SLTU; swap = true; break;
401                 case COND_L:    mc = LOONG_SLT; break;
402                 case COND_G:    mc = LOONG_SLT; swap = true; break;
403                 default:        internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
404         }
405         if (swap) {
406                 uint8_t *argx = arg2;
407                 arg2 = arg3;
408                 arg3 = argx;
409         }
410         cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
411         return true;
414 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
416         uint32_t mc;
417         uint8_t *arg1 = ctx->code_position;
418         uint8_t *arg2 = arg1 + arg_size(*arg1);
419         uint8_t *arg3 = arg2 + arg_size(*arg2);
420         ctx->code_position = arg3 + arg_size(*arg3);
422         if (arg3[0] == ARG_IMM) {
423                 int64_t imm = get_imm(&arg3[1]);
424                 if (alu == ALU_SUB) {
425                         imm = -(uint64_t)imm;
426                         alu = ALU_ADD;
427                 }
428                 if (alu == ALU_ADD) {
429                         if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
430                                 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
431                 } else {
432                         if (unlikely(imm < 0) || unlikely(imm >= 0x1000))
433                                 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
434                 }
435                 switch (alu) {
436                         case ALU_ADD:   mc = size == OP_SIZE_8 ? LOONG_ADDI_D : LOONG_ADDI_W; break;
437                         case ALU_XOR:   mc = LOONG_XORI; break;
438                         case ALU_OR:    mc = LOONG_ORI; break;
439                         case ALU_AND:   mc = LOONG_ANDI; break;
440                         default:        internal(file_line, "cgen_alu: invalid alu %u", alu);
441                 }
442                 cgen_2ri12(mc, arg1[0], arg2[0], imm);
443                 return true;
444         }
446         switch (alu) {
447                 case ALU_ADD:   mc = size == OP_SIZE_8 ? LOONG_ADD_D : LOONG_ADD_W; break;
448                 case ALU_SUB:   mc = size == OP_SIZE_8 ? LOONG_SUB_D : LOONG_SUB_W; break;
449                 case ALU_XOR:   mc = LOONG_XOR; break;
450                 case ALU_OR:    mc = LOONG_OR; break;
451                 case ALU_AND:   mc = LOONG_AND; break;
452                 case ALU_ANDN:  mc = LOONG_ANDN; break;
453                 case ALU_ORN:   mc = LOONG_ORN; break;
454                 case ALU_MUL:   mc = size == OP_SIZE_8 ? LOONG_MUL_D : LOONG_MUL_W; break;
455                 case ALU_SMULH: mc = size == OP_SIZE_8 ? LOONG_MULH_D : LOONG_MULH_W; break;
456                 case ALU_UDIV:  mc = size == OP_SIZE_8 ? LOONG_DIV_DU : LOONG_DIV_WU; break;
457                 case ALU_SDIV:  mc = size == OP_SIZE_8 ? LOONG_DIV_D : LOONG_DIV_W; break;
458                 case ALU_UREM:  mc = size == OP_SIZE_8 ? LOONG_MOD_DU : LOONG_MOD_WU; break;
459                 case ALU_SREM:  mc = size == OP_SIZE_8 ? LOONG_MOD_D : LOONG_MOD_W; break;
460                 default:        internal(file_line, "cgen_alu: invalid alu %u", alu);
461         }
462         cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
463         return true;
466 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
468         uint8_t *arg1 = ctx->code_position;
469         uint8_t *arg2 = arg1 + arg_size(*arg1);
470         ctx->code_position = arg2 + arg_size(*arg2);
471         switch (alu) {
472                 case ALU1_NOT:
473                         cgen_3r(LOONG_NOR, arg1[0], R_ZERO, arg2[0]);
474                         return true;
475                 case ALU1_NEG:
476                         cgen_3r(size == OP_SIZE_4 ? LOONG_SUB_W : LOONG_SUB_D, arg1[0], R_ZERO, arg2[0]);
477                         return true;
478                 case ALU1_INC:
479                         cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], 1);
480                         return true;
481                 case ALU1_DEC:
482                         cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], -1);
483                         return true;
484                 case ALU1_BSWAP:
485                         if (size == OP_SIZE_4) {
486                                 cgen_2r(LOONG_REVB_2H, arg1[0], arg2[0]);
487                                 cgen_2ri8(LOONG_ROTRI_W, arg1[0], arg1[0], 0x10);
488                                 return true;
489                         } else {
490                                 cgen_2r(LOONG_REVB_4H, arg1[0], arg2[0]);
491                                 cgen_2r(LOONG_REVH_D, arg1[0], arg1[0]);
492                                 return true;
493                         }
494                 case ALU1_BSWAP16:
495                         cgen_2r(size == OP_SIZE_4 ? LOONG_REVB_2H : LOONG_REVB_4H, arg1[0], arg2[0]);
496                         return true;
497                 case ALU1_BREV:
498                         cgen_2r(size == OP_SIZE_4 ? LOONG_BITREV_W : LOONG_BITREV_D, arg1[0], arg2[0]);
499                         return true;
500                 case ALU1_BSF:
501                         cgen_2r(size == OP_SIZE_4 ? LOONG_CTZ_W : LOONG_CTZ_D, arg1[0], arg2[0]);
502                         return true;
503                 case ALU1_LZCNT:
504                         cgen_2r(size == OP_SIZE_4 ? LOONG_CLZ_W : LOONG_CLZ_D, arg1[0], arg2[0]);
505                         return true;
506                 default:
507                         internal(file_line, "cgen_alu1: invalid alu %u", alu);
508                         return false;
509         }
512 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
514         uint32_t mc;
515         uint8_t *arg1 = ctx->code_position;
516         uint8_t *arg2 = arg1 + arg_size(*arg1);
517         uint8_t *arg3 = arg2 + arg_size(*arg2);
518         ctx->code_position = arg3 + arg_size(*arg3);
519         if (arg3[0] == ARG_IMM) {
520                 int64_t imm = get_imm(&arg3[1]);
521                 if (alu == ROT_ROL)
522                         imm = -(uint64_t)imm;
523                 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
524                 switch (alu) {
525                         case ROT_ROL:   mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
526                         case ROT_ROR:   mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
527                         case ROT_SHL:   mc = size == OP_SIZE_4 ? LOONG_SLLI_W : LOONG_SLLI_D; break;
528                         case ROT_SHR:   mc = size == OP_SIZE_4 ? LOONG_SRLI_W : LOONG_SRLI_D; break;
529                         case ROT_SAR:   mc = size == OP_SIZE_4 ? LOONG_SRAI_W : LOONG_SRAI_D; break;
530                         default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
531                 }
532                 cgen_2ri8(mc, arg1[0], arg2[0], imm);
533                 return true;
534         }
535         switch (alu) {
536                 case ROT_ROR:   mc = size == OP_SIZE_4 ? LOONG_ROTR_W : LOONG_ROTR_D; break;
537                 case ROT_SHL:   mc = size == OP_SIZE_4 ? LOONG_SLL_W : LOONG_SLL_D; break;
538                 case ROT_SHR:   mc = size == OP_SIZE_4 ? LOONG_SRL_W : LOONG_SRL_D; break;
539                 case ROT_SAR:   mc = size == OP_SIZE_4 ? LOONG_SRA_W : LOONG_SRA_D; break;
540                 default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
541         }
542         cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
543         return true;
546 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
548         int64_t imm;
549         uint8_t *arg1 = ctx->code_position;
550         uint8_t *arg2 = arg1 + arg_size(*arg1);
551         uint8_t *arg3 = arg2 + arg_size(*arg2);
552         ctx->code_position = arg3 + arg_size(*arg3);
553         if (unlikely(arg3[0] != ARG_IMM))
554                 goto invalid;
555         imm = get_imm(&arg3[1]) & 0x3f;
556         switch (alu) {
557                 case BTX_BTR:
558                         if (unlikely(arg1[0] != arg2[0]))
559                                 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
560                         cgen_2r2i(LOONG_BSTRINS_D, arg1[0], R_ZERO, imm, imm);
561                         return true;
562                 case BTX_BTEXT:
563                         cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], imm, imm);
564                         return true;
565         }
567 invalid:
568         internal(file_line, "cgen_btx: bad arguments: %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
569         return false;
572 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
574         uint64_t imm = 0;
575         uint8_t *arg1 = ctx->code_position;
576         uint8_t *arg2 = arg1 + arg_size(*arg1);
577         uint8_t *arg3 = arg2 + arg_size(*arg2);
578         ctx->code_position = arg3 + arg_size(*arg3);
579         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] != ARG_IMM))
580                 goto invalid;
582         imm = get_imm(&arg3[1]);
584         switch (aux) {
585                 case MOV_MASK_32_64:
586                         if (unlikely(arg1[0] != arg2[0]))
587                                 goto invalid;
588                         cgen_1ri20(LOONG_LU32I_D, arg1[0], imm);
589                         return true;
590                 case MOV_MASK_52_64:
591                         cgen_2ri12(LOONG_LU52I_D, arg1[0], arg2[0], imm);
592                         return true;
593                 default:        goto invalid;
594         }
596 invalid:
597         internal(file_line, "cgen_mov_mask: bad arguments: %02x, %02x, %u, %"PRIxMAX"", arg1[0], arg2[0], aux, (uintmax_t)imm);
598         return false;
601 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
603         uint32_t mc;
604         bool swap;
605         uint8_t *arg1 = ctx->code_position;
606         uint8_t *arg2 = arg1 + arg_size(*arg1);
607         ctx->code_position = arg2 + arg_size(*arg2);
609         mc = op_size == OP_SIZE_4 ? LOONG_FCMP_S : LOONG_FCMP_D;
611         switch (aux) {
612                 case FP_COND_P:         mc |= LOONG_FCMP_UN; swap = false; break;
613                 case FP_COND_NP:        mc |= LOONG_FCMP_OR; swap = false; break;
614                 case FP_COND_E:         mc |= LOONG_FCMP_EQ; swap = false; break;
615                 case FP_COND_NE:        mc |= LOONG_FCMP_NE; swap = false; break;
616                 case FP_COND_A:         mc |= LOONG_FCMP_LT; swap = true; break;
617                 case FP_COND_BE:        mc |= LOONG_FCMP_LE; swap = false; break;
618                 case FP_COND_B:         mc |= LOONG_FCMP_LT; swap = false; break;
619                 case FP_COND_AE:        mc |= LOONG_FCMP_LE; swap = true; break;
620                 default:                internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
621                                         return false;
622         }
624         if (swap) {
625                 uint8_t *argx = arg1;
626                 arg1 = arg2;
627                 arg2 = argx;
628         }
630         cgen_3r(mc, 0, arg1[0] & 0x1f, arg2[0] & 0x1f);
631         return true;
634 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx)
636         unsigned reg = cget_one(ctx);
637         cgen_2r(LOONG_MOVCF2GR, reg, 0);
638         return true;
641 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
643         uint32_t mc;
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         switch (aux) {
649                 case FP_ALU_ADD:        mc = op_size == OP_SIZE_4 ? LOONG_FADD_S : LOONG_FADD_D; break;
650                 case FP_ALU_SUB:        mc = op_size == OP_SIZE_4 ? LOONG_FSUB_S : LOONG_FSUB_D; break;
651                 case FP_ALU_MUL:        mc = op_size == OP_SIZE_4 ? LOONG_FMUL_S : LOONG_FMUL_D; break;
652                 case FP_ALU_DIV:        mc = op_size == OP_SIZE_4 ? LOONG_FDIV_S : LOONG_FDIV_D; break;
653                 default:                internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
654         }
655         cgen_3r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f, arg3[0] & 0x1f);
656         return true;
659 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
661         uint32_t mc;
662         uint8_t *arg1 = ctx->code_position;
663         uint8_t *arg2 = arg1 + arg_size(*arg1);
664         ctx->code_position = arg2 + arg_size(*arg2);
665         switch (aux) {
666                 case FP_ALU1_NEG:       mc = op_size == OP_SIZE_4 ? LOONG_FNEG_S : LOONG_FNEG_D; break;
667                 case FP_ALU1_SQRT:      mc = op_size == OP_SIZE_4 ? LOONG_FSQRT_S : LOONG_FSQRT_D; break;
668                 case FP_ALU1_ROUND:     mc = op_size == OP_SIZE_4 ? LOONG_FRINT_S : LOONG_FRINT_D; break;
669                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
670         }
671         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
672         return true;
675 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
677         uint32_t mc;
678         uint8_t *arg1 = ctx->code_position;
679         uint8_t *arg2 = arg1 + arg_size(*arg1);
680         ctx->code_position = arg2 + arg_size(*arg2);
682         if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
683                 internal(file_line, "cgen_fp_to_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
685         if (int_op_size == OP_SIZE_4) {
686                 if (fp_op_size == OP_SIZE_4)
687                         mc = LOONG_FTINTRZ_W_S;
688                 else
689                         mc = LOONG_FTINTRZ_W_D;
690         } else {
691                 if (fp_op_size == OP_SIZE_4)
692                         mc = LOONG_FTINTRZ_L_S;
693                 else
694                         mc = LOONG_FTINTRZ_L_D;
695         }
696         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
697         return true;
700 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
702         uint32_t mc;
703         uint8_t *arg1 = ctx->code_position;
704         uint8_t *arg2 = arg1 + arg_size(*arg1);
705         ctx->code_position = arg2 + arg_size(*arg2);
707         if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
708                 internal(file_line, "cgen_fp_from_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
710         if (int_op_size == OP_SIZE_4) {
711                 if (fp_op_size == OP_SIZE_4)
712                         mc = LOONG_FFINT_S_W;
713                 else
714                         mc = LOONG_FFINT_D_W;
715         } else {
716                 if (fp_op_size == OP_SIZE_4)
717                         mc = LOONG_FFINT_S_L;
718                 else
719                         mc = LOONG_FFINT_D_L;
720         }
721         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
722         return true;
725 static bool attr_w cgen_jmp(struct codegen_context *ctx)
727         g(add_relocation(ctx, JMP_LONG, 0, NULL));
728         cgen_i26(LOONG_B, 0);
729         return true;
732 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
734         uint32_t mc;
735         bool swap;
737         if (reg1 >= 0x20 || reg2 >= 0x20)
738                 goto invalid;
740         if (length > JMP_SHORTEST)
741                 cond ^= 1;
743         swap = false;
744         switch (cond) {
745                 case COND_B:    mc = LOONG_BLTU; break;
746                 case COND_AE:   mc = LOONG_BGEU; break;
747                 case COND_E:    mc = LOONG_BEQ; break;
748                 case COND_NE:   mc = LOONG_BNE; break;
749                 case COND_BE:   mc = LOONG_BGEU; swap = true; break;
750                 case COND_A:    mc = LOONG_BLTU; swap = true; break;
751                 case COND_L:    mc = LOONG_BLT; break;
752                 case COND_GE:   mc = LOONG_BGE; break;
753                 case COND_LE:   mc = LOONG_BGE; swap = true; break;
754                 case COND_G:    mc = LOONG_BLT; swap = true; break;
755                 default:        goto invalid;
756         }
759         if (swap) {
760                 unsigned regx = reg1;
761                 reg1 = reg2;
762                 reg2 = regx;
763         }
765         if (length == JMP_SHORTEST) {
766                 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
767                 cgen_2ri16(mc, reg2, reg1, 0);
768                 return true;
769         } else {
770                 cgen_2ri16(mc, reg2, reg1, 2);
771                 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
772                 cgen_i26(LOONG_B, 0);
773                 return true;
774         }
776 invalid:
777         internal(file_line, "cgen_jmp_12regs: invalid arguments %02x, %02x", reg1, reg2);
778         return false;
781 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
783         uint32_t mc;
784         uint8_t *arg1 = ctx->code_position;
785         ctx->code_position = arg1 + arg_size(*arg1);
786         if (arg1[0] >= 0x20)
787                 goto invalid;
789         switch (cond) {
790                 case COND_S:
791                 case COND_L:
792                         g(cgen_jmp_12regs(ctx, COND_L, length, arg1[0], R_ZERO, 1));
793                         return true;
794                 case COND_NS:
795                 case COND_GE:
796                         g(cgen_jmp_12regs(ctx, COND_GE, length, arg1[0], R_ZERO, 1));
797                         return true;
798                 case COND_LE:
799                 case COND_G:
800                         g(cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1));
801                         return true;
802         }
804         if (length > JMP_SHORT)
805                 cond ^= 1;
807         switch (cond) {
808                 case COND_E:    mc = LOONG_BEQZ; break;
809                 case COND_NE:   mc = LOONG_BNEZ; break;
810                 default:        goto invalid;
811         }
813         if (length <= JMP_SHORT) {
814                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
815                 cgen_1ri21(mc, arg1[0], 0);
816                 return true;
817         } else {
818                 cgen_1ri21(mc, arg1[0], 2);
819                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
820                 cgen_i26(LOONG_B, 0);
821                 return true;
822         }
824 invalid:
825         internal(file_line, "cgen_jmp_reg: invalid argument %02x, %u", arg1[0], cond);
826         return false;
829 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
831         uint8_t *arg1 = ctx->code_position;
832         uint8_t *arg2 = arg1 + arg_size(*arg1);
833         ctx->code_position = arg2 + arg_size(*arg2);
834         g(cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2));
835         return true;
838 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned length)
840         if (length <= JMP_SHORT) {
841                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
842                 cgen_1ri21(LOONG_BCNEZ, 0, 0);
843                 return true;
844         } else {
845                 cgen_1ri21(LOONG_BCEQZ, 0, 2);
846                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
847                 cgen_i26(LOONG_B, 0);
848                 return true;
849         }
852 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
854         uint32_t mc;
855         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
856         switch (reloc->length) {
857                 case JMP_SHORTEST:
858                         if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
859                                 return false;
860                         memcpy(&mc, ctx->mcode + reloc->position, 4);
861                         mc &= ~(0xffffU << 10);
862                         mc |= (offs & 0xffffU) << 10;
863                         memcpy(ctx->mcode + reloc->position, &mc, 4);
864                         return true;
865                 case JMP_SHORT:
866                         if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
867                                 return false;
868                         memcpy(&mc, ctx->mcode + reloc->position, 4);
869                         mc &= ~((0xffffU << 10) | 0x1fU);
870                         mc |= ((offs & 0xffffU) << 10) | ((offs & 0x1f0000U) >> 16);
871                         memcpy(ctx->mcode + reloc->position, &mc, 4);
872                         return true;
873                 case JMP_LONG:
874                         if (unlikely(offs < -0x2000000) || unlikely(offs >= 0x2000000))
875                                 return false;
876                         memcpy(&mc, ctx->mcode + reloc->position, 4);
877                         mc &= ~((0xffffU << 10) | 0x3ffU);
878                         mc |= ((offs & 0xffffU) << 10) | ((offs & 0x3ff0000U) >> 16);
879                         memcpy(ctx->mcode + reloc->position, &mc, 4);
880                         return true;
881                 default:
882                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
883         }
884         return false;
887 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
889         if (unlikely(insn_writes_flags(insn))) {
890                 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
891                         goto invalid_insn;
892         }
893         /*debug("insn: %08x", (unsigned)insn);*/
894         switch (insn_opcode(insn)) {
895                 case INSN_ENTRY:
896                         g(cgen_entry(ctx));
897                         return true;
898                 case INSN_LABEL:
899                         g(cgen_label(ctx));
900                         return true;
901                 case INSN_RET:
902                         cgen_2ri16(LOONG_JIRL, R_ZERO, R_RA, 0);
903                         return true;
904                 case INSN_CALL_INDIRECT:
905                         g(cgen_jmp_call_indirect(ctx, true));
906                         return true;
907                 case INSN_MOV:
908                         g(cgen_mov(ctx, insn_op_size(insn), false));
909                         return true;
910                 case INSN_MOVSX:
911                         g(cgen_mov(ctx, insn_op_size(insn), true));
912                         return true;
913                 case INSN_CMP_DEST_REG:
914                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
915                                 goto invalid_insn;
916                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
917                         return true;
918                 case INSN_ALU:
919                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
920                                 goto invalid_insn;
921                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
922                         return true;
923                 case INSN_ALU1:
924                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
925                                 goto invalid_insn;
926                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
927                         return true;
928                 case INSN_ROT:
929                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
930                                 goto invalid_insn;
931                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
932                         return true;
933                 case INSN_BTX:
934                         g(cgen_btx(ctx, insn_aux(insn)));
935                         return true;
936                 case INSN_MOV_MASK:
937                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
938                                 goto invalid_insn;
939                         g(cgen_mov_mask(ctx, insn_aux(insn)));
940                         return true;
941                 case INSN_FP_CMP_COND:
942                         g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
943                         return true;
944                 case INSN_FP_TEST_REG:
945                         g(cgen_fp_test_reg(ctx));
946                         return true;
947                 case INSN_FP_ALU:
948                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
949                         return true;
950                 case INSN_FP_ALU1:
951                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
952                         return true;
953                 case INSN_FP_TO_INT32:
954                 case INSN_FP_TO_INT64:
955                         g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
956                         return true;
957                 case INSN_FP_FROM_INT32:
958                 case INSN_FP_FROM_INT64:
959                         g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
960                         return true;
961                 case INSN_JMP:
962                         g(cgen_jmp(ctx));
963                         return true;
964                 case INSN_JMP_REG:
965                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
966                                 goto invalid_insn;
967                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
968                         return true;
969                 case INSN_JMP_2REGS:
970                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
971                                 goto invalid_insn;
972                         g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
973                         return true;
974                 case INSN_JMP_FP_TEST:
975                         g(cgen_jmp_fp_test(ctx, insn_jump_size(insn)));
976                         return true;
977                 case INSN_JMP_INDIRECT:
978                         g(cgen_jmp_call_indirect(ctx, false));
979                         return true;
980                 default:
981                 invalid_insn:
982                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
983                         return false;
984         }