2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #define MIPS_NOP 0x00000000U
20 #define MIPS_SLL 0x00000000U
21 #define MIPS_MOVF 0x00000001U
22 #define MIPS_SRL 0x00000002U
23 #define MIPS_SRA 0x00000003U
24 #define MIPS_SLLV 0x00000004U
25 #define MIPS_SRLV 0x00000006U
26 #define MIPS_SRAV 0x00000007U
27 #define MIPS_JR 0x00000008U
28 #define MIPS_JALR 0x00000009U
29 #define MIPS_MFHI 0x00000010U
30 #define MIPS_MFLO 0x00000012U
31 #define MIPS_DSLLV 0x00000014U
32 #define MIPS_DSRLV 0x00000016U
33 #define MIPS_DSRAV 0x00000017U
34 #define MIPS_MULT 0x00000018U
35 #define MIPS_MULTU 0x00000019U
36 #define MIPS_DIV 0x0000001aU
37 #define MIPS_DIVU 0x0000001bU
38 #define MIPS_DMULT 0x0000001cU
39 #define MIPS_DMULTU 0x0000001dU
40 #define MIPS_DDIV 0x0000001eU
41 #define MIPS_DDIVU 0x0000001fU
42 #define MIPS_ADD 0x00000020U
43 #define MIPS_ADDU 0x00000021U
44 #define MIPS_SUB 0x00000022U
45 #define MIPS_SUBU 0x00000023U
46 #define MIPS_AND 0x00000024U
47 #define MIPS_OR 0x00000025U
48 #define MIPS_XOR 0x00000026U
49 #define MIPS_NOR 0x00000027U
50 #define MIPS_SLT 0x0000002aU
51 #define MIPS_SLTU 0x0000002bU
52 #define MIPS_DADD 0x0000002cU
53 #define MIPS_DADDU 0x0000002dU
54 #define MIPS_DSUB 0x0000002eU
55 #define MIPS_DSUBU 0x0000002fU
56 #define MIPS_DSLL 0x00000038U
57 #define MIPS_DSRL 0x0000003aU
58 #define MIPS_DSRA 0x0000003bU
59 #define MIPS_DSLL32 0x0000003cU
60 #define MIPS_DSRL32 0x0000003eU
61 #define MIPS_DSRA32 0x0000003fU
62 #define MIPS_ROTRV 0x00000046U
63 #define MIPS_DROTRV 0x00000056U
64 #define MIPS_MOVT 0x00010001U
65 #define MIPS_ROTR 0x00200002U
66 #define MIPS_DROTR 0x0020003aU
67 #define MIPS_DROTR32 0x0020003eU
68 #define MIPS_BLTZ 0x04000000U
69 #define MIPS_BGEZ 0x04010000U
70 #define MIPS_BLTZAL 0x04100000U
71 #define MIPS_BGEZAL 0x04110000U
72 #define MIPS_J 0x08000000U
73 #define MIPS_BEQ 0x10000000U
74 #define MIPS_BNE 0x14000000U
75 #define MIPS_BLEZ 0x18000000U
76 #define MIPS_BGTZ 0x1c000000U
77 #define MIPS_ADDI 0x20000000U
78 #define MIPS_ADDIU 0x24000000U
79 #define MIPS_SLTI 0x28000000U
80 #define MIPS_SLTIU 0x2c000000U
81 #define MIPS_ANDI 0x30000000U
82 #define MIPS_ORI 0x34000000U
83 #define MIPS_XORI 0x38000000U
84 #define MIPS_LUI 0x3c000000U
85 #define MIPS_MFC1 0x44000000U
86 #define MIPS_DMFC1 0x44200000U
87 #define MIPS_BC1F 0x45000000U
88 #define MIPS_BC1T 0x45010000U
89 #define MIPS_ADD_FP 0x46000000U
90 #define MIPS_SUB_FP 0x46000001U
91 #define MIPS_MUL_FP 0x46000002U
92 #define MIPS_DIV_FP 0x46000003U
93 #define MIPS_SQRT_FP 0x46000004U
94 #define MIPS_NEG_FP 0x46000007U
95 #define MIPS_TRUNC_L 0x46000009U
96 #define MIPS_TRUNC_W 0x4600000dU
97 #define MIPS_C_F 0x46000030U
98 #define MIPS_C_UN 0x46000031U
99 #define MIPS_C_EQ 0x46000032U
100 #define MIPS_C_UEQ 0x46000033U
101 #define MIPS_C_OLT 0x46000034U
102 #define MIPS_C_ULT 0x46000035U
103 #define MIPS_C_OLE 0x46000036U
104 #define MIPS_C_ULE 0x46000037U
105 #define MIPS_FP_SINGLE 0x00U
106 #define MIPS_FP_DOUBLE 0x01U
107 #define MIPS_CVT_S_W 0x46800020U
108 #define MIPS_CVT_D_W 0x46800021U
109 #define MIPS_CVT_S_L 0x46a00020U
110 #define MIPS_CVT_D_L 0x46a00021U
111 #define MIPS_DADDI 0x60000000U
112 #define MIPS_DADDIU 0x64000000U
113 #define MIPS_LDL 0x68000000U
114 #define MIPS_LDR 0x6c000000U
115 #define MIPS_MUL 0x70000002U
116 #define MIPS_CLZ 0x70000020U
117 #define MIPS_DCLZ 0x70000024U
118 #define MIPS_WSBH 0x7c0000a0U
119 #define MIPS_DSBH 0x7c0000a4U
120 #define MIPS_DSHD 0x7c000164U
121 #define MIPS_SEB 0x7c000420U
122 #define MIPS_SEH 0x7c000620U
123 #define MIPS_LB 0x80000000U
124 #define MIPS_LH 0x84000000U
125 #define MIPS_LWL 0x88000000U
126 #define MIPS_LW 0x8c000000U
127 #define MIPS_LBU 0x90000000U
128 #define MIPS_LHU 0x94000000U
129 #define MIPS_LWR 0x98000000U
130 #define MIPS_LWU 0x9c000000U
131 #define MIPS_SB 0xa0000000U
132 #define MIPS_SH 0xa4000000U
133 #define MIPS_SWL 0xa8000000U
134 #define MIPS_SW 0xac000000U
135 #define MIPS_SDL 0xb0000000U
136 #define MIPS_SDR 0xb4000000U
137 #define MIPS_SWR 0xb8000000U
138 #define MIPS_LWC1 0xc4000000U
139 #define MIPS_LDC1 0xd4000000U
140 #define MIPS_LD 0xdc000000U
141 #define MIPS_SWC1 0xe4000000U
142 #define MIPS_SDC1 0xf4000000U
143 #define MIPS_SD 0xfc000000U
145 #define MIPS_R6_LSA 0x00000005U
146 #define MIPS_R6_JALR 0x00000009U
147 #define MIPS_R6_DLSA 0x00000015U
148 #define MIPS_R6_CLZ 0x00000050U
149 #define MIPS_R6_DCLZ 0x00000052U
150 #define MIPS_R6_MUL 0x00000098U
151 #define MIPS_R6_MULU 0x00000099U
152 #define MIPS_R6_DIV 0x0000009aU
153 #define MIPS_R6_DIVU 0x0000009bU
154 #define MIPS_R6_DMUL 0x0000009cU
155 #define MIPS_R6_DMULU 0x0000009dU
156 #define MIPS_R6_DDIV 0x0000009eU
157 #define MIPS_R6_DDIVU 0x0000009fU
158 #define MIPS_R6_MUH 0x000000d8U
159 #define MIPS_R6_MUHU 0x000000d9U
160 #define MIPS_R6_MOD 0x000000daU
161 #define MIPS_R6_MODU 0x000000dbU
162 #define MIPS_R6_DMUH 0x000000dcU
163 #define MIPS_R6_DMUHU 0x000000ddU
164 #define MIPS_R6_DMOD 0x000000deU
165 #define MIPS_R6_DMODU 0x000000dfU
166 #define MIPS_R6_DAHI 0x04060000U
167 #define MIPS_R6_DATI 0x041e0000U
168 #define MIPS_R6_AUI 0x3c000000U
169 #define MIPS_R6_BC1EQZ 0x45200000U
170 #define MIPS_R6_BC1NEZ 0x45a00000U
171 #define MIPS_R6_CMP_AF 0x46800000U
172 #define MIPS_R6_CMP_UN 0x46800001U
173 #define MIPS_R6_CMP_EQ 0x46800002U
174 #define MIPS_R6_CMP_UEQ 0x46800003U
175 #define MIPS_R6_CMP_LT 0x46800004U
176 #define MIPS_R6_CMP_ULT 0x46800005U
177 #define MIPS_R6_CMP_LE 0x46800006U
178 #define MIPS_R6_CMP_ULE 0x46800007U
179 #define MIPS_R6_CMP_OR 0x46800011U
180 #define MIPS_R6_CMP_UNE 0x46800012U
181 #define MIPS_R6_CMP_NE 0x46800013U
182 #define MIPS_R6_BGEZC 0x58000000U
183 #define MIPS_R6_BLEZC 0x58000000U
184 #define MIPS_R6_BGTZC 0x5c000000U
185 #define MIPS_R6_BLTZC 0x5c000000U
186 #define MIPS_R6_DAUI 0x74000000U
187 #define MIPS_R6_BITSWAP 0x7c000020U
188 #define MIPS_R6_DBITSWAP 0x7c000024U
189 #define MIPS_R6_BC 0xc8000000U
190 #define MIPS_R6_JIC 0xd8000000U
191 #define MIPS_R6_BEQZC 0xd8000000U
192 #define MIPS_R6_JIALC 0xf8000000U
193 #define MIPS_R6_BNEZC 0xf8000000U
195 #define cgen_mips_3reg(mc, rd, rs, rt) \
196 cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rs) << 21) | ((uint32_t)(rt) << 16))
197 #define cgen_mips_rot_imm(mc, rd, rt, sa) \
198 cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rt) << 16) | (((sa) & 0x1f) << 6))
199 #define cgen_mips_imm(mc, rt, rs, imm) \
200 cgen_four((mc) | ((uint32_t)(rt) << 16) | ((uint32_t)(rs) << 21) | ((imm) & 0xffff))
201 #define cgen_mips_fp(mc, fmt, fd, fs, ft) \
202 cgen_four((mc) | ((uint32_t)(fmt) << 21) | ((uint32_t)(fd) << 6) | ((uint32_t)(fs) << 11) | ((uint32_t)(ft) << 16))
204 static bool attr_w cgen_jump_not_last(struct codegen_context *ctx, unsigned insns)
206 if (MIPS_R4000_ERRATA) {
207 while (unlikely((ctx->mcode_size & 0xfffU) + insns * 4 >= 0x1000U)) {
214 static bool attr_w cgen_ls(struct codegen_context *ctx, uint32_t mc, uint8_t arg1, uint8_t *arg2)
216 int64_t imm = get_imm(&arg2[2]);
217 if (unlikely(imm != (int16_t)imm))
218 internal(file_line, "cgen_ls: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
219 cgen_mips_imm(mc, arg1, arg2[1], imm);
223 static uint32_t cgen_fp_fmt(unsigned op_size)
226 case OP_SIZE_4: return MIPS_FP_SINGLE;
227 case OP_SIZE_8: return MIPS_FP_DOUBLE;
228 default: internal(file_line, "cgen_fp_fmt: invalid size %u", op_size);
233 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
237 uint8_t *arg1 = ctx->code_position;
238 uint8_t *arg2 = arg1 + arg_size(*arg1);
239 ctx->code_position = arg2 + arg_size(*arg2);
242 if (sx && size == OP_SIZE_1) {
243 cgen_mips_3reg(MIPS_SEB, arg1[0], 0, arg2[0]);
246 if (sx && size == OP_SIZE_2) {
247 cgen_mips_3reg(MIPS_SEH, arg1[0], 0, arg2[0]);
250 if (unlikely(size != OP_SIZE_NATIVE))
251 internal(file_line, "cgen_mov: unsupported size %u", size);
252 cgen_mips_3reg(MIPS_OR, arg1[0], arg2[0], R_ZERO);
256 uint32_t fmt = cgen_fp_fmt(size);
257 cgen_mips_fp(MIPS_MFC1, fmt, 0, arg2[0] & 31, arg1[0]);
260 if (arg2[0] == ARG_IMM) {
261 imm = get_imm(&arg2[1]);
262 if (unlikely((imm & 0xffff) != 0) || unlikely(imm != (int32_t)imm))
263 internal(file_line, "cgen_mov: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
264 cgen_mips_imm(MIPS_LUI, arg1[0], 0, (uint64_t)imm >> 16);
267 if (arg2[0] == ARG_ADDRESS_1) {
268 if (!sx && size != OP_SIZE_NATIVE)
269 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LBU : size == OP_SIZE_2 ? MIPS_LHU : MIPS_LWU, arg1[0], arg2));
271 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LB : size == OP_SIZE_2 ? MIPS_LH : size == OP_SIZE_4 ? MIPS_LW : MIPS_LD, arg1[0], arg2));
272 if (MIPS_LOAD_DELAY_SLOTS)
281 g(cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_LWC1 : MIPS_LDC1, arg1[0] & 31, arg2));
282 if (MIPS_LOAD_DELAY_SLOTS)
286 if (arg1[0] == ARG_ADDRESS_1) {
287 if (arg2[0] == ARG_IMM) {
288 imm = get_imm(&arg2[1]);
289 if (unlikely(imm != 0))
294 return cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_SB : size == OP_SIZE_2 ? MIPS_SH : size == OP_SIZE_4 ? MIPS_SW : MIPS_SD, arg2[0], arg1);
297 return cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_SWC1 : MIPS_SDC1, arg2[0] & 31, arg1);
303 internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u, %u", arg1[0], arg2[0], size, (unsigned)sx);
307 static bool attr_w cgen_mov_lr(struct codegen_context *ctx, unsigned size, bool r)
311 uint8_t *arg1, *arg2, *arg3;
312 arg1 = ctx->code_position;
313 arg2 = arg1 + arg_size(*arg1);
314 arg3 = arg2 + arg_size(*arg2);
315 ctx->code_position = arg3 + arg_size(*arg3);
317 if (unlikely(arg1[0] != arg2[0]))
320 if (arg1[0] < 32 && arg3[0] == ARG_ADDRESS_1) {
321 imm = get_imm(&arg3[2]);
323 mc = size == OP_SIZE_4 ? MIPS_LWL : MIPS_LDL;
325 mc = size == OP_SIZE_4 ? MIPS_LWR : MIPS_LDR;
326 cgen_mips_imm(mc, arg1[0], arg3[1], imm);
327 if (MIPS_LOAD_DELAY_SLOTS)
330 } if (arg1[0] == ARG_ADDRESS_1 && arg3[0] < 32) {
331 imm = get_imm(&arg1[2]);
333 mc = size == OP_SIZE_4 ? MIPS_SWL : MIPS_SDL;
335 mc = size == OP_SIZE_4 ? MIPS_SWR : MIPS_SDR;
336 cgen_mips_imm(mc, arg3[0], arg1[1], imm);
341 internal(file_line, "cgen_mov_lr: invalid parameters %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
345 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
350 uint8_t *arg1 = ctx->code_position;
351 uint8_t *arg2 = arg1 + arg_size(*arg1);
352 uint8_t *arg3 = arg2 + arg_size(*arg2);
353 ctx->code_position = arg3 + arg_size(*arg3);
354 if (arg3[0] == ARG_IMM) {
355 int64_t imm = get_imm(&arg3[1]);
356 if (unlikely(imm != (int16_t)imm))
357 internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
359 case COND_B: mc = MIPS_SLTIU; break;
360 case COND_L: mc = MIPS_SLTI; break;
361 default: goto invalid;
363 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
366 if (arg2[0] == ARG_IMM) {
367 int64_t imm = get_imm(&arg2[1]);
368 if (unlikely(imm != 0))
369 internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
373 case COND_B: mc = MIPS_SLTU; break;
374 case COND_A: mc = MIPS_SLTU; swap = true; break;
375 case COND_L: mc = MIPS_SLT; break;
376 case COND_G: mc = MIPS_SLT; swap = true; break;
377 default: goto invalid;
380 uint8_t *argx = arg2;
384 cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
388 internal(file_line, "cgen_cmp_dest_reg: invalid arguments %u, %02x, %02x, %02x", aux, arg1[0], arg2[0], arg3[0]);
392 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
396 bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
397 uint8_t *arg1 = ctx->code_position;
398 uint8_t *arg2 = arg1 + arg_size(*arg1);
399 uint8_t *arg3 = arg2 + arg_size(*arg2);
400 ctx->code_position = arg3 + arg_size(*arg3);
402 if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
403 uint8_t *arg_swp = arg3;
407 if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
409 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL))
411 shift = arg3[1] & ARG_SHIFT_AMOUNT;
412 if (unlikely(shift < 1) || unlikely(shift > 4))
414 mc = size == OP_SIZE_8 ? MIPS_R6_DLSA : MIPS_R6_LSA;
415 mc |= (shift - 1) << 6;
416 cgen_mips_3reg(mc, arg1[0], arg3[2], arg2[0]);
420 if ((alu == ALU_ADD || alu == ALU_SUB) && arg3[0] == ARG_IMM && trap && !have_imm_trap) {
421 imm = get_imm(&arg3[1]);
422 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, imm);
423 g(cgen_trap(ctx, cget_four(ctx)));
425 mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
427 mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
428 cgen_mips_3reg(mc, arg1[0], arg2[0], R_AT);
431 if (MIPS_R6 && alu == ALU_ADD && arg3[0] == ARG_IMM && !trap) {
432 imm = get_imm(&arg3[1]);
433 if (imm && !(imm & 0xffff)) {
434 if (imm == (int32_t)imm) {
435 cgen_mips_imm(size == OP_SIZE_4 ? MIPS_R6_AUI : MIPS_R6_DAUI, arg1[0], arg2[0], (uint64_t)imm >> 16);
438 if (imm & 0xFFFFFFFFLL)
440 imm /= 0x100000000LL;
441 if (imm == (int16_t)imm && size == OP_SIZE_8) {
442 if (unlikely(arg1[0] != arg2[0]))
444 cgen_mips_imm(MIPS_R6_DAHI, 0, arg1[0], imm);
450 if (size == OP_SIZE_8) {
451 if (unlikely(arg1[0] != arg2[0]))
453 cgen_mips_imm(MIPS_R6_DATI, 0, arg1[0], imm);
461 g(cgen_trap(ctx, cget_four(ctx)));
466 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUL : MIPS_R6_DMUL, arg1[0], arg2[0], arg3[0]);
469 if (size == OP_SIZE_4 && MIPS_HAS_MUL) {
470 cgen_mips_3reg(MIPS_MUL, arg1[0], arg2[0], arg3[0]);
473 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
474 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
478 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUHU : MIPS_R6_DMUHU, arg1[0], arg2[0], arg3[0]);
481 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
482 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
486 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUH : MIPS_R6_DMUH, arg1[0], arg2[0], arg3[0]);
489 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg2[0], arg3[0]);
490 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
494 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIVU : MIPS_R6_DDIVU, arg1[0], arg2[0], arg3[0]);
497 g(cgen_jump_not_last(ctx, 1));
498 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
499 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
503 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIV : MIPS_R6_DDIV, arg1[0], arg2[0], arg3[0]);
506 g(cgen_jump_not_last(ctx, 1));
507 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
508 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
512 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MODU : MIPS_R6_DMODU, arg1[0], arg2[0], arg3[0]);
515 g(cgen_jump_not_last(ctx, 1));
516 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
517 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
521 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MOD : MIPS_R6_DMOD, arg1[0], arg2[0], arg3[0]);
524 g(cgen_jump_not_last(ctx, 1));
525 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
526 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
530 if (arg3[0] == ARG_IMM) {
531 imm = get_imm(&arg3[1]);
532 if (alu == ALU_SUB) {
533 imm = -(uint64_t)imm;
537 case ALU_ADD: if (trap) mc = size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI;
538 else mc = size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU;
540 case ALU_XOR: mc = MIPS_XORI; break;
541 case ALU_OR: mc = MIPS_ORI; break;
542 case ALU_AND: mc = MIPS_ANDI; break;
543 default: goto invalid;
545 if (unlikely(imm != (alu == ALU_ADD ? (int64_t)(int16_t)imm : (int64_t)(uint16_t)imm)))
546 internal(file_line, "cgen_alu: invalid imm: %"PRIxMAX" (%u)", (uintmax_t)imm, alu);
547 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
552 case ALU_ADD: if (trap) mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
553 else mc = size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU;
555 case ALU_SUB: if (trap) mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
556 else mc = size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU;
558 case ALU_XOR: mc = MIPS_XOR; break;
559 case ALU_OR: mc = MIPS_OR; break;
560 case ALU_AND: mc = MIPS_AND; break;
561 default: goto invalid;
563 cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
567 internal(file_line, "cgen_alu: invalid alu %u, %u, %"PRIxMAX"", size, alu, (uintmax_t)imm);
571 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
573 bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
574 int cnst = alu == ALU1_INC ? 1 : alu == ALU1_DEC ? -1 : 0;
575 uint8_t *arg1 = ctx->code_position;
576 uint8_t *arg2 = arg1 + arg_size(*arg1);
577 ctx->code_position = arg2 + arg_size(*arg2);
579 if (cnst && trap && !have_imm_trap) {
580 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
581 g(cgen_trap(ctx, cget_four(ctx)));
582 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD, arg1[0], arg2[0], R_AT);
585 if (MIPS_R4000_ERRATA && cnst && !trap && size == OP_SIZE_8) { /* R4000 has broken DADDIU */
586 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
587 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, arg1[0], arg2[0], R_AT);
592 g(cgen_trap(ctx, cget_four(ctx)));
595 case ALU1_NOT: cgen_mips_3reg(MIPS_NOR, arg1[0], R_ZERO, arg2[0]);
597 case ALU1_NEG: if (trap) cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB, arg1[0], R_ZERO, arg2[0]);
598 else cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, arg1[0], R_ZERO, arg2[0]);
601 case ALU1_DEC: if (trap) cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI, arg1[0], arg2[0], cnst);
602 else cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, arg1[0], arg2[0], cnst);
604 case ALU1_LZCNT: if (!MIPS_R6)
605 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DCLZ : MIPS_CLZ, arg1[0], arg2[0], arg1[0]);
607 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DCLZ : MIPS_R6_CLZ, arg1[0], arg2[0], 0);
610 bswap: if (size == OP_SIZE_4) {
611 cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
612 cgen_mips_rot_imm(MIPS_ROTR, arg1[0], arg1[0], 16);
614 cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
615 cgen_mips_3reg(MIPS_DSHD, arg1[0], 0, arg1[0]);
618 case ALU1_BSWAP16:if (size == OP_SIZE_4) {
619 cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
621 cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
624 case ALU1_BREV: cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DBITSWAP : MIPS_R6_BITSWAP, arg1[0], 0, arg2[0]);
627 default: goto invalid;
631 internal(file_line, "cgen_alu1: invalid alu %u, %u", size, alu);
635 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
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);
643 if (arg3[0] == ARG_IMM) {
644 int64_t imm = get_imm(&arg3[1]);
646 case ROT_SHL: mc = size == OP_SIZE_4 ? MIPS_SLL : imm & 0x20 ? MIPS_DSLL32 : MIPS_DSLL; break;
647 case ROT_SHR: mc = size == OP_SIZE_4 ? MIPS_SRL : imm & 0x20 ? MIPS_DSRL32 : MIPS_DSRL; break;
648 case ROT_SAR: mc = size == OP_SIZE_4 ? MIPS_SRA : imm & 0x20 ? MIPS_DSRA32 : MIPS_DSRA; break;
649 case ROT_ROR: mc = size == OP_SIZE_4 ? MIPS_ROTR : imm & 0x20 ? MIPS_DROTR32 : MIPS_DROTR; break;
650 default: goto invalid;
652 cgen_mips_rot_imm(mc, arg1[0], arg2[0], imm);
656 case ROT_SHL: mc = size == OP_SIZE_4 ? MIPS_SLLV : MIPS_DSLLV; break;
657 case ROT_SHR: mc = size == OP_SIZE_4 ? MIPS_SRLV : MIPS_DSRLV; break;
658 case ROT_SAR: mc = size == OP_SIZE_4 ? MIPS_SRAV : MIPS_DSRAV; break;
659 case ROT_ROR: mc = size == OP_SIZE_4 ? MIPS_ROTRV : MIPS_DROTRV; break;
660 default: goto invalid;
662 cgen_mips_3reg(mc, arg1[0], arg3[0], arg2[0]);
667 internal(file_line, "cgen_rot: invalid rotation %u, %u", size, alu);
671 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size)
673 uint8_t *arg1, *arg2, *arg3, *arg4;
674 arg1 = ctx->code_position;
675 arg2 = arg1 + arg_size(*arg1);
676 arg3 = arg2 + arg_size(*arg2);
677 arg4 = arg3 + arg_size(*arg3);
678 ctx->code_position = arg4 + arg_size(*arg4);
680 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg3[0], arg4[0]);
681 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
682 cgen_mips_3reg(MIPS_MFHI, arg2[0], 0, 0);
687 static bool fp_condition_negated(unsigned aux)
690 case FP_COND_P: return false;
691 case FP_COND_E: return false;
692 case FP_COND_B: return false;
693 case FP_COND_BE: return false;
694 case FP_COND_NP: return true;
695 case FP_COND_NE: return true;
696 case FP_COND_AE: return true;
697 case FP_COND_A: return true;
698 default: internal(file_line, "fp_condition_negated: invalid condition %u", aux);
703 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
706 uint8_t *arg1 = ctx->code_position;
707 uint8_t *arg2 = arg1 + arg_size(*arg1);
708 ctx->code_position = arg2 + arg_size(*arg2);
712 case FP_COND_P: mc = MIPS_R6_CMP_UN; break;
713 case FP_COND_E: mc = MIPS_R6_CMP_EQ; break;
714 case FP_COND_B: mc = MIPS_R6_CMP_LT; break;
715 case FP_COND_BE: mc = MIPS_R6_CMP_LE; break;
716 case FP_COND_NP: mc = MIPS_R6_CMP_UN; break;
717 case FP_COND_NE: mc = MIPS_R6_CMP_EQ; break;
718 case FP_COND_AE: mc = MIPS_R6_CMP_LT; break;
719 case FP_COND_A: mc = MIPS_R6_CMP_LE; break;
720 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
725 case FP_COND_P: mc = MIPS_C_UN; break;
726 case FP_COND_E: mc = MIPS_C_EQ; break;
727 case FP_COND_B: mc = MIPS_C_OLT; break;
728 case FP_COND_BE: mc = MIPS_C_OLE; break;
729 case FP_COND_NP: mc = MIPS_C_UN; break;
730 case FP_COND_NE: mc = MIPS_C_EQ; break;
731 case FP_COND_AE: mc = MIPS_C_OLT; break;
732 case FP_COND_A: mc = MIPS_C_OLE; break;
733 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
737 fmt = cgen_fp_fmt(op_size);
738 cgen_mips_fp(mc, fmt, MIPS_R6 ? FR_CMP_RESULT & 31 : 0, arg1[0] & 31, arg2[0] & 31);
739 if (MIPS_FCMP_DELAY_SLOTS)
744 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx, unsigned aux)
746 unsigned reg = cget_one(ctx);
748 cgen_mips_fp(MIPS_MFC1, MIPS_FP_SINGLE, 0, FR_CMP_RESULT & 31, reg);
749 if (OP_SIZE_NATIVE > OP_SIZE_4) {
750 cgen_mips_rot_imm(MIPS_SLL, reg, reg, 0);
752 if (!fp_condition_negated(aux)) {
753 cgen_mips_3reg(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, reg, R_ZERO, reg);
755 cgen_mips_imm(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, reg, reg, 1);
758 } else if (MIPS_HAS_MOVT) {
759 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
760 cgen_mips_3reg(!fp_condition_negated(aux) ? MIPS_MOVF : MIPS_MOVT, reg, R_ZERO, 0);
762 g(cgen_jump_not_last(ctx, 1));
763 cgen_mips_imm(!fp_condition_negated(aux) ? MIPS_BC1T : MIPS_BC1F, 0, 0, 2);
764 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
765 cgen_mips_3reg(MIPS_OR, reg, R_ZERO, R_ZERO);
770 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
773 uint8_t *arg1 = ctx->code_position;
774 uint8_t *arg2 = arg1 + arg_size(*arg1);
775 uint8_t *arg3 = arg2 + arg_size(*arg2);
776 ctx->code_position = arg3 + arg_size(*arg3);
778 case FP_ALU_ADD: mc = MIPS_ADD_FP; break;
779 case FP_ALU_SUB: mc = MIPS_SUB_FP; break;
780 case FP_ALU_MUL: mc = MIPS_MUL_FP; break;
781 case FP_ALU_DIV: mc = MIPS_DIV_FP; break;
782 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
784 fmt = cgen_fp_fmt(op_size);
785 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
789 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
792 uint8_t *arg1 = ctx->code_position;
793 uint8_t *arg2 = arg1 + arg_size(*arg1);
794 ctx->code_position = arg2 + arg_size(*arg2);
796 case FP_ALU1_NEG: mc = MIPS_NEG_FP; break;
797 case FP_ALU1_SQRT: mc = MIPS_SQRT_FP; break;
798 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
800 fmt = cgen_fp_fmt(op_size);
801 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
805 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
808 uint8_t *arg1 = ctx->code_position;
809 uint8_t *arg2 = arg1 + arg_size(*arg1);
810 ctx->code_position = arg2 + arg_size(*arg2);
811 switch (int_op_size) {
812 case OP_SIZE_4: mc = MIPS_TRUNC_W; break;
813 case OP_SIZE_8: mc = MIPS_TRUNC_L; break;
814 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
816 fmt = cgen_fp_fmt(fp_op_size);
817 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
821 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
824 uint8_t *arg1 = ctx->code_position;
825 uint8_t *arg2 = arg1 + arg_size(*arg1);
826 ctx->code_position = arg2 + arg_size(*arg2);
828 if (int_op_size == OP_SIZE_4) {
829 if (fp_op_size == OP_SIZE_4)
834 if (fp_op_size == OP_SIZE_4)
839 cgen_mips_fp(mc, 0, arg1[0] & 31, arg2[0] & 31, 0);
843 static unsigned cgen_jmp_extra_long_length(void)
845 return !MIPS_R6 ? 6 : 5;
848 static bool attr_w cgen_jmp_extra_long(struct codegen_context *ctx)
850 cgen_mips_imm(MIPS_LUI, R_AT, 0, 0);
851 cgen_mips_imm(MIPS_BGEZAL, 0, R_ZERO, 1);
852 cgen_mips_imm(MIPS_ORI, R_AT, R_AT, 0);
853 cgen_mips_3reg(OP_SIZE_ADDRESS == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, R_AT, R_AT, R_RA);
855 cgen_mips_3reg(MIPS_JR, 0, R_AT, 0);
858 cgen_mips_imm(MIPS_R6_JIC, R_AT, 0, 0);
863 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
865 if (MIPS_R6 && length <= JMP_LONG) {
866 g(cgen_jump_not_last(ctx, 1));
867 g(add_relocation(ctx, JMP_LONG, 0, NULL));
868 cgen_four(MIPS_R6_BC);
871 if (length == JMP_SHORTEST) {
872 g(cgen_jump_not_last(ctx, 1));
873 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
874 cgen_mips_imm(MIPS_BEQ, R_ZERO, R_ZERO, 0);
878 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length()));
879 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
880 g(cgen_jmp_extra_long(ctx));
884 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
887 uint8_t *arg1 = ctx->code_position;
888 ctx->code_position = arg1 + arg_size(*arg1);
893 if (MIPS_R6 && (cond == COND_E || cond == COND_NE) && length <= JMP_SHORT) {
894 mc = cond == COND_E ? MIPS_R6_BEQZC : MIPS_R6_BNEZC;
895 g(cgen_jump_not_last(ctx, 1));
896 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
897 cgen_four(mc | ((uint32_t)arg1[0] << 21));
902 if (length > JMP_SHORTEST)
906 case COND_E: mc = MIPS_BEQ; break;
907 case COND_NE: mc = MIPS_BNE; break;
909 case COND_L: mc = MIPS_BLTZ; break;
910 case COND_LE: mc = MIPS_BLEZ; break;
911 case COND_G: mc = MIPS_BGTZ; break;
913 case COND_GE: mc = MIPS_BGEZ; break;
914 default: goto invalid;
917 if (length == JMP_SHORTEST) {
918 g(cgen_jump_not_last(ctx, 1));
919 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
920 cgen_mips_imm(mc, 0, arg1[0], 0);
924 if (MIPS_R6 && length <= JMP_LONG) {
925 g(cgen_jump_not_last(ctx, 3));
926 cgen_mips_imm(mc, 0, arg1[0], 2);
928 g(add_relocation(ctx, JMP_LONG, 1, NULL));
929 cgen_four(MIPS_R6_BC);
932 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
933 cgen_mips_imm(mc, 0, arg1[0], cgen_jmp_extra_long_length());
934 g(add_relocation(ctx, JMP_EXTRA_LONG, 1, NULL));
935 g(cgen_jmp_extra_long(ctx));
939 internal(file_line, "cgen_jmp_reg: invalid arguments %u, %u, %02x", cond, length, arg1[0]);
943 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
946 uint8_t *arg1 = ctx->code_position;
947 uint8_t *arg2 = arg1 + arg_size(*arg1);
948 ctx->code_position = arg2 + arg_size(*arg2);
949 if (arg1[0] >= 0x20 || arg2[0] >= 0x20 || (cond != COND_E && cond != COND_NE))
952 if (length > JMP_SHORTEST)
955 mc = cond == COND_E ? MIPS_BEQ : MIPS_BNE;
957 if (length == JMP_SHORTEST) {
958 g(cgen_jump_not_last(ctx, 1));
959 g(add_relocation(ctx, JMP_SHORTEST, 2, NULL));
960 cgen_mips_imm(mc, arg1[0], arg2[0], 0);
964 if (MIPS_R6 && length <= JMP_LONG) {
965 g(cgen_jump_not_last(ctx, 3));
966 cgen_mips_imm(mc, arg1[0], arg2[0], 2);
968 g(add_relocation(ctx, JMP_LONG, 1, NULL));
969 cgen_four(MIPS_R6_BC);
972 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
973 cgen_mips_imm(mc, arg1[0], arg2[0], cgen_jmp_extra_long_length());
974 g(add_relocation(ctx, JMP_EXTRA_LONG, 2, NULL));
975 g(cgen_jmp_extra_long(ctx));
979 internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
983 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned aux, unsigned length)
987 if (fp_condition_negated(aux))
989 if (length > JMP_SHORTEST)
992 mc = t ? MIPS_R6_BC1NEZ : MIPS_R6_BC1EQZ;
993 if (length == JMP_SHORTEST) {
994 g(cgen_jump_not_last(ctx, 1));
995 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
996 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 0);
1000 if (length <= JMP_LONG) {
1001 g(cgen_jump_not_last(ctx, 3));
1002 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 2);
1003 cgen_four(MIPS_NOP);
1004 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1005 cgen_four(MIPS_R6_BC);
1008 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1009 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, cgen_jmp_extra_long_length());
1010 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1011 g(cgen_jmp_extra_long(ctx));
1014 mc = t ? MIPS_BC1T : MIPS_BC1F;
1015 if (length == JMP_SHORTEST) {
1016 g(cgen_jump_not_last(ctx, 1));
1017 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1018 cgen_mips_imm(mc, 0, 0, 0);
1019 cgen_four(MIPS_NOP);
1022 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1023 cgen_mips_imm(mc, 0, 0, cgen_jmp_extra_long_length());
1024 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1025 g(cgen_jmp_extra_long(ctx));
1030 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, unsigned reg, bool call)
1032 g(cgen_jump_not_last(ctx, 1));
1035 cgen_mips_3reg(MIPS_JR, 0, reg, 0);
1036 cgen_four(MIPS_NOP);
1038 cgen_mips_imm(MIPS_R6_JIC, reg, 0, 0);
1042 cgen_mips_3reg(MIPS_JALR, R_RA, reg, 0);
1043 cgen_four(MIPS_NOP);
1045 cgen_mips_imm(MIPS_R6_JIALC, reg, 0, 0);
1052 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1055 int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1056 switch (reloc->length) {
1060 if (offs != (int16_t)offs)
1062 memcpy(&mc, ctx->mcode + reloc->position, 4);
1064 mc |= offs & 0xFFFFU;
1065 memcpy(ctx->mcode + reloc->position, &mc, 4);
1070 if (offs < -0x00100000 || offs >= 0x00100000)
1072 memcpy(&mc, ctx->mcode + reloc->position, 4);
1074 mc |= offs & 0x001FFFFFU;
1075 memcpy(ctx->mcode + reloc->position, &mc, 4);
1080 if (offs < -0x02000000 || offs >= 0x02000000)
1082 memcpy(&mc, ctx->mcode + reloc->position, 4);
1084 mc |= offs & 0x03FFFFFFU;
1085 memcpy(ctx->mcode + reloc->position, &mc, 4);
1087 case JMP_EXTRA_LONG:
1089 if (offs != (int32_t)offs)
1091 memcpy(&mc, ctx->mcode + reloc->position, 4);
1093 mc |= ((uint64_t)offs >> 16) & 0xFFFFU;
1094 memcpy(ctx->mcode + reloc->position, &mc, 4);
1095 memcpy(&mc, ctx->mcode + reloc->position + 8, 4);
1097 mc |= offs & 0xFFFFU;
1098 memcpy(ctx->mcode + reloc->position + 8, &mc, 4);
1101 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1107 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1109 if (unlikely(insn_writes_flags(insn))) {
1110 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
1113 switch (insn_opcode(insn)) {
1121 g(cgen_jmp_call_indirect(ctx, R_RA, false));
1123 cgen_four(MIPS_NOP);
1125 case INSN_CALL_INDIRECT:
1126 g(cgen_jmp_call_indirect(ctx, cget_one(ctx), true));
1129 g(cgen_mov(ctx, insn_op_size(insn), false));
1132 g(cgen_mov(ctx, insn_op_size(insn), true));
1135 g(cgen_mov_lr(ctx, insn_op_size(insn), insn_aux(insn) != 0));
1137 case INSN_CMP_DEST_REG:
1138 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1140 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
1143 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1145 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), false));
1148 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1150 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), true));
1153 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1155 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
1157 case INSN_ALU1_TRAP:
1158 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1160 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
1163 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1165 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
1168 if (unlikely(insn_op_size(insn) <= OP_SIZE_2) || unlikely(insn_op_size(insn) > OP_SIZE_NATIVE))
1170 g(cgen_mul_l(ctx, insn_op_size(insn)));
1172 case INSN_FP_CMP_COND:
1173 g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
1175 case INSN_FP_TEST_REG:
1176 g(cgen_fp_test_reg(ctx, insn_aux(insn)));
1179 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1182 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1184 case INSN_FP_TO_INT32:
1185 case INSN_FP_TO_INT64:
1186 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1188 case INSN_FP_FROM_INT32:
1189 case INSN_FP_FROM_INT64:
1190 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1193 g(cgen_jmp(ctx, insn_jump_size(insn)));
1196 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1198 case INSN_JMP_2REGS:
1199 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
1201 case INSN_JMP_FP_TEST:
1202 g(cgen_jmp_fp_test(ctx, insn_aux(insn), insn_jump_size(insn)));
1204 case INSN_JMP_INDIRECT:
1205 g(cgen_jmp_call_indirect(ctx, cget_one(ctx), false));
1209 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);