codegen: support hacked ABI if using pointer compression
[ajla.git] / c2-loong.inc
blob9304cc2773a4a70c094c14c2d94155d79b3ef763
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_BSWAP:
479                         if (size == OP_SIZE_4) {
480                                 cgen_2r(LOONG_REVB_2H, arg1[0], arg2[0]);
481                                 cgen_2ri8(LOONG_ROTRI_W, arg1[0], arg1[0], 0x10);
482                                 return true;
483                         } else {
484                                 cgen_2r(LOONG_REVB_4H, arg1[0], arg2[0]);
485                                 cgen_2r(LOONG_REVH_D, arg1[0], arg1[0]);
486                                 return true;
487                         }
488                 case ALU1_BSWAP16:
489                         cgen_2r(size == OP_SIZE_4 ? LOONG_REVB_2H : LOONG_REVB_4H, arg1[0], arg2[0]);
490                         return true;
491                 case ALU1_BREV:
492                         cgen_2r(size == OP_SIZE_4 ? LOONG_BITREV_W : LOONG_BITREV_D, arg1[0], arg2[0]);
493                         return true;
494                 case ALU1_BSF:
495                         cgen_2r(size == OP_SIZE_4 ? LOONG_CTZ_W : LOONG_CTZ_D, arg1[0], arg2[0]);
496                         return true;
497                 case ALU1_LZCNT:
498                         cgen_2r(size == OP_SIZE_4 ? LOONG_CLZ_W : LOONG_CLZ_D, arg1[0], arg2[0]);
499                         return true;
500                 default:
501                         internal(file_line, "cgen_alu1: invalid alu %u", alu);
502                         return false;
503         }
506 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
508         uint32_t mc;
509         uint8_t *arg1 = ctx->code_position;
510         uint8_t *arg2 = arg1 + arg_size(*arg1);
511         uint8_t *arg3 = arg2 + arg_size(*arg2);
512         ctx->code_position = arg3 + arg_size(*arg3);
513         if (arg3[0] == ARG_IMM) {
514                 int64_t imm = get_imm(&arg3[1]);
515                 if (alu == ROT_ROL)
516                         imm = -(uint64_t)imm;
517                 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
518                 switch (alu) {
519                         case ROT_ROL:   mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
520                         case ROT_ROR:   mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
521                         case ROT_SHL:   mc = size == OP_SIZE_4 ? LOONG_SLLI_W : LOONG_SLLI_D; break;
522                         case ROT_SHR:   mc = size == OP_SIZE_4 ? LOONG_SRLI_W : LOONG_SRLI_D; break;
523                         case ROT_SAR:   mc = size == OP_SIZE_4 ? LOONG_SRAI_W : LOONG_SRAI_D; break;
524                         default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
525                 }
526                 cgen_2ri8(mc, arg1[0], arg2[0], imm);
527                 return true;
528         }
529         switch (alu) {
530                 case ROT_ROR:   mc = size == OP_SIZE_4 ? LOONG_ROTR_W : LOONG_ROTR_D; break;
531                 case ROT_SHL:   mc = size == OP_SIZE_4 ? LOONG_SLL_W : LOONG_SLL_D; break;
532                 case ROT_SHR:   mc = size == OP_SIZE_4 ? LOONG_SRL_W : LOONG_SRL_D; break;
533                 case ROT_SAR:   mc = size == OP_SIZE_4 ? LOONG_SRA_W : LOONG_SRA_D; break;
534                 default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
535         }
536         cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
537         return true;
540 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
542         int64_t imm;
543         uint8_t *arg1 = ctx->code_position;
544         uint8_t *arg2 = arg1 + arg_size(*arg1);
545         uint8_t *arg3 = arg2 + arg_size(*arg2);
546         ctx->code_position = arg3 + arg_size(*arg3);
547         if (unlikely(arg3[0] != ARG_IMM))
548                 goto invalid;
549         imm = get_imm(&arg3[1]) & 0x3f;
550         switch (alu) {
551                 case BTX_BTR:
552                         if (unlikely(arg1[0] != arg2[0]))
553                                 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
554                         cgen_2r2i(LOONG_BSTRINS_D, arg1[0], R_ZERO, imm, imm);
555                         return true;
556                 case BTX_BTEXT:
557                         cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], imm, imm);
558                         return true;
559         }
561 invalid:
562         internal(file_line, "cgen_btx: bad arguments: %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
563         return false;
566 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
568         uint64_t imm = 0;
569         uint8_t *arg1 = ctx->code_position;
570         uint8_t *arg2 = arg1 + arg_size(*arg1);
571         uint8_t *arg3 = arg2 + arg_size(*arg2);
572         ctx->code_position = arg3 + arg_size(*arg3);
573         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] != ARG_IMM))
574                 goto invalid;
576         imm = get_imm(&arg3[1]);
578         switch (aux) {
579                 case MOV_MASK_32_64:
580                         if (unlikely(arg1[0] != arg2[0]))
581                                 goto invalid;
582                         cgen_1ri20(LOONG_LU32I_D, arg1[0], imm);
583                         return true;
584                 case MOV_MASK_52_64:
585                         cgen_2ri12(LOONG_LU52I_D, arg1[0], arg2[0], imm);
586                         return true;
587                 default:        goto invalid;
588         }
590 invalid:
591         internal(file_line, "cgen_mov_mask: bad arguments: %02x, %02x, %u, %"PRIxMAX"", arg1[0], arg2[0], aux, (uintmax_t)imm);
592         return false;
595 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
597         uint32_t mc;
598         bool swap;
599         uint8_t *arg1 = ctx->code_position;
600         uint8_t *arg2 = arg1 + arg_size(*arg1);
601         ctx->code_position = arg2 + arg_size(*arg2);
603         mc = op_size == OP_SIZE_4 ? LOONG_FCMP_S : LOONG_FCMP_D;
605         switch (aux) {
606                 case FP_COND_P:         mc |= LOONG_FCMP_UN; swap = false; break;
607                 case FP_COND_NP:        mc |= LOONG_FCMP_OR; swap = false; break;
608                 case FP_COND_E:         mc |= LOONG_FCMP_EQ; swap = false; break;
609                 case FP_COND_NE:        mc |= LOONG_FCMP_NE; swap = false; break;
610                 case FP_COND_A:         mc |= LOONG_FCMP_LT; swap = true; break;
611                 case FP_COND_BE:        mc |= LOONG_FCMP_LE; swap = false; break;
612                 case FP_COND_B:         mc |= LOONG_FCMP_LT; swap = false; break;
613                 case FP_COND_AE:        mc |= LOONG_FCMP_LE; swap = true; break;
614                 default:                internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
615                                         return false;
616         }
618         if (swap) {
619                 uint8_t *argx = arg1;
620                 arg1 = arg2;
621                 arg2 = argx;
622         }
624         cgen_3r(mc, 0, arg1[0] & 0x1f, arg2[0] & 0x1f);
625         return true;
628 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx)
630         unsigned reg = cget_one(ctx);
631         cgen_2r(LOONG_MOVCF2GR, reg, 0);
632         return true;
635 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
637         uint32_t mc;
638         uint8_t *arg1 = ctx->code_position;
639         uint8_t *arg2 = arg1 + arg_size(*arg1);
640         uint8_t *arg3 = arg2 + arg_size(*arg2);
641         ctx->code_position = arg3 + arg_size(*arg3);
642         switch (aux) {
643                 case FP_ALU_ADD:        mc = op_size == OP_SIZE_4 ? LOONG_FADD_S : LOONG_FADD_D; break;
644                 case FP_ALU_SUB:        mc = op_size == OP_SIZE_4 ? LOONG_FSUB_S : LOONG_FSUB_D; break;
645                 case FP_ALU_MUL:        mc = op_size == OP_SIZE_4 ? LOONG_FMUL_S : LOONG_FMUL_D; break;
646                 case FP_ALU_DIV:        mc = op_size == OP_SIZE_4 ? LOONG_FDIV_S : LOONG_FDIV_D; break;
647                 default:                internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
648         }
649         cgen_3r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f, arg3[0] & 0x1f);
650         return true;
653 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
655         uint32_t mc;
656         uint8_t *arg1 = ctx->code_position;
657         uint8_t *arg2 = arg1 + arg_size(*arg1);
658         ctx->code_position = arg2 + arg_size(*arg2);
659         switch (aux) {
660                 case FP_ALU1_NEG:       mc = op_size == OP_SIZE_4 ? LOONG_FNEG_S : LOONG_FNEG_D; break;
661                 case FP_ALU1_SQRT:      mc = op_size == OP_SIZE_4 ? LOONG_FSQRT_S : LOONG_FSQRT_D; break;
662                 case FP_ALU1_ROUND:     mc = op_size == OP_SIZE_4 ? LOONG_FRINT_S : LOONG_FRINT_D; break;
663                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
664         }
665         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
666         return true;
669 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
671         uint32_t mc;
672         uint8_t *arg1 = ctx->code_position;
673         uint8_t *arg2 = arg1 + arg_size(*arg1);
674         ctx->code_position = arg2 + arg_size(*arg2);
676         if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
677                 internal(file_line, "cgen_fp_to_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
679         if (int_op_size == OP_SIZE_4) {
680                 if (fp_op_size == OP_SIZE_4)
681                         mc = LOONG_FTINTRZ_W_S;
682                 else
683                         mc = LOONG_FTINTRZ_W_D;
684         } else {
685                 if (fp_op_size == OP_SIZE_4)
686                         mc = LOONG_FTINTRZ_L_S;
687                 else
688                         mc = LOONG_FTINTRZ_L_D;
689         }
690         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
691         return true;
694 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
696         uint32_t mc;
697         uint8_t *arg1 = ctx->code_position;
698         uint8_t *arg2 = arg1 + arg_size(*arg1);
699         ctx->code_position = arg2 + arg_size(*arg2);
701         if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
702                 internal(file_line, "cgen_fp_from_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
704         if (int_op_size == OP_SIZE_4) {
705                 if (fp_op_size == OP_SIZE_4)
706                         mc = LOONG_FFINT_S_W;
707                 else
708                         mc = LOONG_FFINT_D_W;
709         } else {
710                 if (fp_op_size == OP_SIZE_4)
711                         mc = LOONG_FFINT_S_L;
712                 else
713                         mc = LOONG_FFINT_D_L;
714         }
715         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
716         return true;
719 static bool attr_w cgen_jmp(struct codegen_context *ctx)
721         g(add_relocation(ctx, JMP_LONG, 0, NULL));
722         cgen_i26(LOONG_B, 0);
723         return true;
726 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
728         uint32_t mc;
729         bool swap;
731         if (reg1 >= 0x20 || reg2 >= 0x20)
732                 goto invalid;
734         if (length > JMP_SHORTEST)
735                 cond ^= 1;
737         swap = false;
738         switch (cond) {
739                 case COND_B:    mc = LOONG_BLTU; break;
740                 case COND_AE:   mc = LOONG_BGEU; break;
741                 case COND_E:    mc = LOONG_BEQ; break;
742                 case COND_NE:   mc = LOONG_BNE; break;
743                 case COND_BE:   mc = LOONG_BGEU; swap = true; break;
744                 case COND_A:    mc = LOONG_BLTU; swap = true; break;
745                 case COND_L:    mc = LOONG_BLT; break;
746                 case COND_GE:   mc = LOONG_BGE; break;
747                 case COND_LE:   mc = LOONG_BGE; swap = true; break;
748                 case COND_G:    mc = LOONG_BLT; swap = true; break;
749                 default:        goto invalid;
750         }
753         if (swap) {
754                 unsigned regx = reg1;
755                 reg1 = reg2;
756                 reg2 = regx;
757         }
759         if (length == JMP_SHORTEST) {
760                 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
761                 cgen_2ri16(mc, reg2, reg1, 0);
762                 return true;
763         } else {
764                 cgen_2ri16(mc, reg2, reg1, 2);
765                 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
766                 cgen_i26(LOONG_B, 0);
767                 return true;
768         }
770 invalid:
771         internal(file_line, "cgen_jmp_12regs: invalid arguments %02x, %02x", reg1, reg2);
772         return false;
775 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
777         uint32_t mc;
778         uint8_t *arg1 = ctx->code_position;
779         ctx->code_position = arg1 + arg_size(*arg1);
780         if (arg1[0] >= 0x20)
781                 goto invalid;
783         switch (cond) {
784                 case COND_S:
785                 case COND_L:
786                         g(cgen_jmp_12regs(ctx, COND_L, length, arg1[0], R_ZERO, 1));
787                         return true;
788                 case COND_NS:
789                 case COND_GE:
790                         g(cgen_jmp_12regs(ctx, COND_GE, length, arg1[0], R_ZERO, 1));
791                         return true;
792                 case COND_LE:
793                 case COND_G:
794                         g(cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1));
795                         return true;
796         }
798         if (length > JMP_SHORT)
799                 cond ^= 1;
801         switch (cond) {
802                 case COND_E:    mc = LOONG_BEQZ; break;
803                 case COND_NE:   mc = LOONG_BNEZ; break;
804                 default:        goto invalid;
805         }
807         if (length <= JMP_SHORT) {
808                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
809                 cgen_1ri21(mc, arg1[0], 0);
810                 return true;
811         } else {
812                 cgen_1ri21(mc, arg1[0], 2);
813                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
814                 cgen_i26(LOONG_B, 0);
815                 return true;
816         }
818 invalid:
819         internal(file_line, "cgen_jmp_reg: invalid argument %02x, %u", arg1[0], cond);
820         return false;
823 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
825         uint8_t *arg1 = ctx->code_position;
826         uint8_t *arg2 = arg1 + arg_size(*arg1);
827         ctx->code_position = arg2 + arg_size(*arg2);
828         g(cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2));
829         return true;
832 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned length)
834         if (length <= JMP_SHORT) {
835                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
836                 cgen_1ri21(LOONG_BCNEZ, 0, 0);
837                 return true;
838         } else {
839                 cgen_1ri21(LOONG_BCEQZ, 0, 2);
840                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
841                 cgen_i26(LOONG_B, 0);
842                 return true;
843         }
846 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
848         uint32_t mc;
849         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
850         switch (reloc->length) {
851                 case JMP_SHORTEST:
852                         if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
853                                 return false;
854                         memcpy(&mc, ctx->mcode + reloc->position, 4);
855                         mc &= ~(0xffffU << 10);
856                         mc |= (offs & 0xffffU) << 10;
857                         memcpy(ctx->mcode + reloc->position, &mc, 4);
858                         return true;
859                 case JMP_SHORT:
860                         if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
861                                 return false;
862                         memcpy(&mc, ctx->mcode + reloc->position, 4);
863                         mc &= ~((0xffffU << 10) | 0x1fU);
864                         mc |= ((offs & 0xffffU) << 10) | ((offs & 0x1f0000U) >> 16);
865                         memcpy(ctx->mcode + reloc->position, &mc, 4);
866                         return true;
867                 case JMP_LONG:
868                         if (unlikely(offs < -0x2000000) || unlikely(offs >= 0x2000000))
869                                 return false;
870                         memcpy(&mc, ctx->mcode + reloc->position, 4);
871                         mc &= ~((0xffffU << 10) | 0x3ffU);
872                         mc |= ((offs & 0xffffU) << 10) | ((offs & 0x3ff0000U) >> 16);
873                         memcpy(ctx->mcode + reloc->position, &mc, 4);
874                         return true;
875                 default:
876                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
877         }
878         return false;
881 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
883         if (unlikely(insn_writes_flags(insn))) {
884                 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
885                         goto invalid_insn;
886         }
887         /*debug("insn: %08x", (unsigned)insn);*/
888         switch (insn_opcode(insn)) {
889                 case INSN_ENTRY:
890                         g(cgen_entry(ctx));
891                         return true;
892                 case INSN_LABEL:
893                         g(cgen_label(ctx));
894                         return true;
895                 case INSN_RET:
896                         cgen_2ri16(LOONG_JIRL, R_ZERO, R_RA, 0);
897                         return true;
898                 case INSN_CALL_INDIRECT:
899                         g(cgen_jmp_call_indirect(ctx, true));
900                         return true;
901                 case INSN_MOV:
902                         g(cgen_mov(ctx, insn_op_size(insn), false));
903                         return true;
904                 case INSN_MOVSX:
905                         g(cgen_mov(ctx, insn_op_size(insn), true));
906                         return true;
907                 case INSN_CMP_DEST_REG:
908                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
909                                 goto invalid_insn;
910                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
911                         return true;
912                 case INSN_ALU:
913                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
914                                 goto invalid_insn;
915                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
916                         return true;
917                 case INSN_ALU1:
918                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
919                                 goto invalid_insn;
920                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
921                         return true;
922                 case INSN_ROT:
923                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
924                                 goto invalid_insn;
925                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
926                         return true;
927                 case INSN_BTX:
928                         g(cgen_btx(ctx, insn_aux(insn)));
929                         return true;
930                 case INSN_MOV_MASK:
931                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
932                                 goto invalid_insn;
933                         g(cgen_mov_mask(ctx, insn_aux(insn)));
934                         return true;
935                 case INSN_FP_CMP_COND:
936                         g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
937                         return true;
938                 case INSN_FP_TEST_REG:
939                         g(cgen_fp_test_reg(ctx));
940                         return true;
941                 case INSN_FP_ALU:
942                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
943                         return true;
944                 case INSN_FP_ALU1:
945                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
946                         return true;
947                 case INSN_FP_TO_INT32:
948                 case INSN_FP_TO_INT64:
949                         g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
950                         return true;
951                 case INSN_FP_FROM_INT32:
952                 case INSN_FP_FROM_INT64:
953                         g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
954                         return true;
955                 case INSN_JMP:
956                         g(cgen_jmp(ctx));
957                         return true;
958                 case INSN_JMP_REG:
959                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
960                                 goto invalid_insn;
961                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
962                         return true;
963                 case INSN_JMP_2REGS:
964                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
965                                 goto invalid_insn;
966                         g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
967                         return true;
968                 case INSN_JMP_FP_TEST:
969                         g(cgen_jmp_fp_test(ctx, insn_jump_size(insn)));
970                         return true;
971                 case INSN_JMP_INDIRECT:
972                         g(cgen_jmp_call_indirect(ctx, false));
973                         return true;
974                 default:
975                 invalid_insn:
976                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
977                         return false;
978         }