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_MTC1 0x44800000U
88 #define MIPS_DMTC1 0x44a00000U
89 #define MIPS_BC1F 0x45000000U
90 #define MIPS_BC1T 0x45010000U
91 #define MIPS_ADD_FP 0x46000000U
92 #define MIPS_SUB_FP 0x46000001U
93 #define MIPS_MUL_FP 0x46000002U
94 #define MIPS_DIV_FP 0x46000003U
95 #define MIPS_SQRT_FP 0x46000004U
96 #define MIPS_MOV_FP 0x46000006U
97 #define MIPS_NEG_FP 0x46000007U
98 #define MIPS_TRUNC_L 0x46000009U
99 #define MIPS_TRUNC_W 0x4600000dU
100 #define MIPS_C_F 0x46000030U
101 #define MIPS_C_UN 0x46000031U
102 #define MIPS_C_EQ 0x46000032U
103 #define MIPS_C_UEQ 0x46000033U
104 #define MIPS_C_OLT 0x46000034U
105 #define MIPS_C_ULT 0x46000035U
106 #define MIPS_C_OLE 0x46000036U
107 #define MIPS_C_ULE 0x46000037U
108 #define MIPS_FP_SINGLE 0x00U
109 #define MIPS_FP_DOUBLE 0x01U
110 #define MIPS_CVT_S_W 0x46800020U
111 #define MIPS_CVT_D_W 0x46800021U
112 #define MIPS_CVT_S_L 0x46a00020U
113 #define MIPS_CVT_D_L 0x46a00021U
114 #define MIPS_DADDI 0x60000000U
115 #define MIPS_DADDIU 0x64000000U
116 #define MIPS_LDL 0x68000000U
117 #define MIPS_LDR 0x6c000000U
118 #define MIPS_MUL 0x70000002U
119 #define MIPS_CLZ 0x70000020U
120 #define MIPS_DCLZ 0x70000024U
121 #define MIPS_WSBH 0x7c0000a0U
122 #define MIPS_DSBH 0x7c0000a4U
123 #define MIPS_DSHD 0x7c000164U
124 #define MIPS_SEB 0x7c000420U
125 #define MIPS_SEH 0x7c000620U
126 #define MIPS_LB 0x80000000U
127 #define MIPS_LH 0x84000000U
128 #define MIPS_LWL 0x88000000U
129 #define MIPS_LW 0x8c000000U
130 #define MIPS_LBU 0x90000000U
131 #define MIPS_LHU 0x94000000U
132 #define MIPS_LWR 0x98000000U
133 #define MIPS_LWU 0x9c000000U
134 #define MIPS_SB 0xa0000000U
135 #define MIPS_SH 0xa4000000U
136 #define MIPS_SWL 0xa8000000U
137 #define MIPS_SW 0xac000000U
138 #define MIPS_SDL 0xb0000000U
139 #define MIPS_SDR 0xb4000000U
140 #define MIPS_SWR 0xb8000000U
141 #define MIPS_LWC1 0xc4000000U
142 #define MIPS_LDC1 0xd4000000U
143 #define MIPS_LD 0xdc000000U
144 #define MIPS_SWC1 0xe4000000U
145 #define MIPS_SDC1 0xf4000000U
146 #define MIPS_SD 0xfc000000U
148 #define MIPS_R6_LSA 0x00000005U
149 #define MIPS_R6_JALR 0x00000009U
150 #define MIPS_R6_DLSA 0x00000015U
151 #define MIPS_R6_CLZ 0x00000050U
152 #define MIPS_R6_DCLZ 0x00000052U
153 #define MIPS_R6_MUL 0x00000098U
154 #define MIPS_R6_MULU 0x00000099U
155 #define MIPS_R6_DIV 0x0000009aU
156 #define MIPS_R6_DIVU 0x0000009bU
157 #define MIPS_R6_DMUL 0x0000009cU
158 #define MIPS_R6_DMULU 0x0000009dU
159 #define MIPS_R6_DDIV 0x0000009eU
160 #define MIPS_R6_DDIVU 0x0000009fU
161 #define MIPS_R6_MUH 0x000000d8U
162 #define MIPS_R6_MUHU 0x000000d9U
163 #define MIPS_R6_MOD 0x000000daU
164 #define MIPS_R6_MODU 0x000000dbU
165 #define MIPS_R6_DMUH 0x000000dcU
166 #define MIPS_R6_DMUHU 0x000000ddU
167 #define MIPS_R6_DMOD 0x000000deU
168 #define MIPS_R6_DMODU 0x000000dfU
169 #define MIPS_R6_DAHI 0x04060000U
170 #define MIPS_R6_DATI 0x041e0000U
171 #define MIPS_R6_AUI 0x3c000000U
172 #define MIPS_R6_BC1EQZ 0x45200000U
173 #define MIPS_R6_BC1NEZ 0x45a00000U
174 #define MIPS_R6_CMP_AF 0x46800000U
175 #define MIPS_R6_CMP_UN 0x46800001U
176 #define MIPS_R6_CMP_EQ 0x46800002U
177 #define MIPS_R6_CMP_UEQ 0x46800003U
178 #define MIPS_R6_CMP_LT 0x46800004U
179 #define MIPS_R6_CMP_ULT 0x46800005U
180 #define MIPS_R6_CMP_LE 0x46800006U
181 #define MIPS_R6_CMP_ULE 0x46800007U
182 #define MIPS_R6_CMP_OR 0x46800011U
183 #define MIPS_R6_CMP_UNE 0x46800012U
184 #define MIPS_R6_CMP_NE 0x46800013U
185 #define MIPS_R6_BGEZC 0x58000000U
186 #define MIPS_R6_BLEZC 0x58000000U
187 #define MIPS_R6_BGTZC 0x5c000000U
188 #define MIPS_R6_BLTZC 0x5c000000U
189 #define MIPS_R6_DAUI 0x74000000U
190 #define MIPS_R6_BITSWAP 0x7c000020U
191 #define MIPS_R6_DBITSWAP 0x7c000024U
192 #define MIPS_R6_BC 0xc8000000U
193 #define MIPS_R6_JIC 0xd8000000U
194 #define MIPS_R6_BEQZC 0xd8000000U
195 #define MIPS_R6_JIALC 0xf8000000U
196 #define MIPS_R6_BNEZC 0xf8000000U
198 #define cgen_mips_3reg(mc, rd, rs, rt) \
199 cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rs) << 21) | ((uint32_t)(rt) << 16))
200 #define cgen_mips_rot_imm(mc, rd, rt, sa) \
201 cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rt) << 16) | (((sa) & 0x1f) << 6))
202 #define cgen_mips_imm(mc, rt, rs, imm) \
203 cgen_four((mc) | ((uint32_t)(rt) << 16) | ((uint32_t)(rs) << 21) | ((imm) & 0xffff))
204 #define cgen_mips_fp(mc, fmt, fd, fs, ft) \
205 cgen_four((mc) | ((uint32_t)(fmt) << 21) | ((uint32_t)(fd) << 6) | ((uint32_t)(fs) << 11) | ((uint32_t)(ft) << 16))
207 static bool attr_w cgen_jump_not_last(struct codegen_context *ctx, unsigned insns)
209 if (MIPS_R4000_ERRATA) {
210 while (unlikely((ctx->mcode_size & 0xfffU) + insns * 4 >= 0x1000U)) {
217 static bool attr_w cgen_ls(struct codegen_context *ctx, uint32_t mc, uint8_t arg1, uint8_t *arg2)
219 int64_t imm = get_imm(&arg2[2]);
220 if (unlikely(imm != (int16_t)imm))
221 internal(file_line, "cgen_ls: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
222 cgen_mips_imm(mc, arg1, arg2[1], imm);
226 static uint32_t cgen_fp_fmt(unsigned op_size)
229 case OP_SIZE_4: return MIPS_FP_SINGLE;
230 case OP_SIZE_8: return MIPS_FP_DOUBLE;
231 default: internal(file_line, "cgen_fp_fmt: invalid size %u", op_size);
236 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
240 uint8_t *arg1 = ctx->code_position;
241 uint8_t *arg2 = arg1 + arg_size(*arg1);
242 ctx->code_position = arg2 + arg_size(*arg2);
245 if (sx && size == OP_SIZE_1) {
246 cgen_mips_3reg(MIPS_SEB, arg1[0], 0, arg2[0]);
249 if (sx && size == OP_SIZE_2) {
250 cgen_mips_3reg(MIPS_SEH, arg1[0], 0, arg2[0]);
253 if (unlikely(size != OP_SIZE_NATIVE))
254 internal(file_line, "cgen_mov: unsupported size %u", size);
255 cgen_mips_3reg(MIPS_OR, arg1[0], arg2[0], R_ZERO);
258 if (reg_is_fp(arg2[0])) {
259 uint32_t fmt = cgen_fp_fmt(size);
260 cgen_mips_fp(MIPS_MFC1, fmt, 0, arg2[0] & 31, arg1[0]);
263 if (arg2[0] == ARG_IMM) {
264 imm = get_imm(&arg2[1]);
265 if (unlikely((imm & 0xffff) != 0) || unlikely(imm != (int32_t)imm))
266 internal(file_line, "cgen_mov: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
267 cgen_mips_imm(MIPS_LUI, arg1[0], 0, (uint64_t)imm >> 16);
270 if (arg2[0] == ARG_ADDRESS_1) {
271 if (!sx && size != OP_SIZE_NATIVE)
272 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LBU : size == OP_SIZE_2 ? MIPS_LHU : MIPS_LWU, arg1[0], arg2));
274 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));
275 if (MIPS_LOAD_DELAY_SLOTS)
281 if (reg_is_fp(arg1[0])) {
283 uint32_t fmt = cgen_fp_fmt(size);
284 cgen_mips_fp(MIPS_MTC1, fmt, 0, arg1[0] & 31, arg2[0]);
287 if (reg_is_fp(arg2[0])) {
288 uint32_t fmt = cgen_fp_fmt(size);
289 uint32_t mc = MIPS_MOV_FP;
290 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
293 g(cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_LWC1 : MIPS_LDC1, arg1[0] & 31, arg2));
294 if (MIPS_LOAD_DELAY_SLOTS)
298 if (arg1[0] == ARG_ADDRESS_1) {
299 if (arg2[0] == ARG_IMM) {
300 imm = get_imm(&arg2[1]);
301 if (unlikely(imm != 0))
306 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);
308 if (reg_is_fp(arg2[0])) {
309 return cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_SWC1 : MIPS_SDC1, arg2[0] & 31, arg1);
315 internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u, %u", arg1[0], arg2[0], size, (unsigned)sx);
319 static bool attr_w cgen_mov_lr(struct codegen_context *ctx, unsigned size, bool r)
323 uint8_t *arg1, *arg2, *arg3;
324 arg1 = ctx->code_position;
325 arg2 = arg1 + arg_size(*arg1);
326 arg3 = arg2 + arg_size(*arg2);
327 ctx->code_position = arg3 + arg_size(*arg3);
329 if (unlikely(arg1[0] != arg2[0]))
332 if (arg1[0] < 32 && arg3[0] == ARG_ADDRESS_1) {
333 imm = get_imm(&arg3[2]);
335 mc = size == OP_SIZE_4 ? MIPS_LWL : MIPS_LDL;
337 mc = size == OP_SIZE_4 ? MIPS_LWR : MIPS_LDR;
338 cgen_mips_imm(mc, arg1[0], arg3[1], imm);
339 if (MIPS_LOAD_DELAY_SLOTS)
342 } if (arg1[0] == ARG_ADDRESS_1 && arg3[0] < 32) {
343 imm = get_imm(&arg1[2]);
345 mc = size == OP_SIZE_4 ? MIPS_SWL : MIPS_SDL;
347 mc = size == OP_SIZE_4 ? MIPS_SWR : MIPS_SDR;
348 cgen_mips_imm(mc, arg3[0], arg1[1], imm);
353 internal(file_line, "cgen_mov_lr: invalid parameters %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
357 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
362 uint8_t *arg1 = ctx->code_position;
363 uint8_t *arg2 = arg1 + arg_size(*arg1);
364 uint8_t *arg3 = arg2 + arg_size(*arg2);
365 ctx->code_position = arg3 + arg_size(*arg3);
366 if (arg3[0] == ARG_IMM) {
367 int64_t imm = get_imm(&arg3[1]);
368 if (unlikely(imm != (int16_t)imm))
369 internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
371 case COND_B: mc = MIPS_SLTIU; break;
372 case COND_L: mc = MIPS_SLTI; break;
373 default: goto invalid;
375 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
378 if (arg2[0] == ARG_IMM) {
379 int64_t imm = get_imm(&arg2[1]);
380 if (unlikely(imm != 0))
381 internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
385 case COND_B: mc = MIPS_SLTU; break;
386 case COND_A: mc = MIPS_SLTU; swap = true; break;
387 case COND_L: mc = MIPS_SLT; break;
388 case COND_G: mc = MIPS_SLT; swap = true; break;
389 default: goto invalid;
392 uint8_t *argx = arg2;
396 cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
400 internal(file_line, "cgen_cmp_dest_reg: invalid arguments %u, %02x, %02x, %02x", aux, arg1[0], arg2[0], arg3[0]);
404 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
408 bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
409 uint8_t *arg1 = ctx->code_position;
410 uint8_t *arg2 = arg1 + arg_size(*arg1);
411 uint8_t *arg3 = arg2 + arg_size(*arg2);
412 ctx->code_position = arg3 + arg_size(*arg3);
414 if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
415 uint8_t *arg_swp = arg3;
419 if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
421 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL))
423 shift = arg3[1] & ARG_SHIFT_AMOUNT;
424 if (unlikely(shift < 1) || unlikely(shift > 4))
426 mc = size == OP_SIZE_8 ? MIPS_R6_DLSA : MIPS_R6_LSA;
427 mc |= (shift - 1) << 6;
428 cgen_mips_3reg(mc, arg1[0], arg3[2], arg2[0]);
432 if ((alu == ALU_ADD || alu == ALU_SUB) && arg3[0] == ARG_IMM && trap && !have_imm_trap) {
433 imm = get_imm(&arg3[1]);
434 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, imm);
435 g(cgen_trap(ctx, cget_four(ctx)));
437 mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
439 mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
440 cgen_mips_3reg(mc, arg1[0], arg2[0], R_AT);
443 if (MIPS_R6 && alu == ALU_ADD && arg3[0] == ARG_IMM && !trap) {
444 imm = get_imm(&arg3[1]);
445 if (imm && !(imm & 0xffff)) {
446 if (imm == (int32_t)imm) {
447 cgen_mips_imm(size == OP_SIZE_4 ? MIPS_R6_AUI : MIPS_R6_DAUI, arg1[0], arg2[0], (uint64_t)imm >> 16);
450 if (imm & 0xFFFFFFFFLL)
452 imm /= 0x100000000LL;
453 if (imm == (int16_t)imm && size == OP_SIZE_8) {
454 if (unlikely(arg1[0] != arg2[0]))
456 cgen_mips_imm(MIPS_R6_DAHI, 0, arg1[0], imm);
462 if (size == OP_SIZE_8) {
463 if (unlikely(arg1[0] != arg2[0]))
465 cgen_mips_imm(MIPS_R6_DATI, 0, arg1[0], imm);
473 g(cgen_trap(ctx, cget_four(ctx)));
478 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUL : MIPS_R6_DMUL, arg1[0], arg2[0], arg3[0]);
481 if (size == OP_SIZE_4 && MIPS_HAS_MUL) {
482 cgen_mips_3reg(MIPS_MUL, arg1[0], arg2[0], arg3[0]);
485 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
486 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
490 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUHU : MIPS_R6_DMUHU, arg1[0], arg2[0], arg3[0]);
493 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
494 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
498 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUH : MIPS_R6_DMUH, arg1[0], arg2[0], arg3[0]);
501 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg2[0], arg3[0]);
502 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
506 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIVU : MIPS_R6_DDIVU, arg1[0], arg2[0], arg3[0]);
509 g(cgen_jump_not_last(ctx, 1));
510 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
511 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
515 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIV : MIPS_R6_DDIV, arg1[0], arg2[0], arg3[0]);
518 g(cgen_jump_not_last(ctx, 1));
519 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
520 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
524 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MODU : MIPS_R6_DMODU, arg1[0], arg2[0], arg3[0]);
527 g(cgen_jump_not_last(ctx, 1));
528 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
529 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
533 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MOD : MIPS_R6_DMOD, arg1[0], arg2[0], arg3[0]);
536 g(cgen_jump_not_last(ctx, 1));
537 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
538 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
542 if (arg3[0] == ARG_IMM) {
543 imm = get_imm(&arg3[1]);
544 if (alu == ALU_SUB) {
545 imm = -(uint64_t)imm;
549 case ALU_ADD: if (trap) mc = size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI;
550 else mc = size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU;
552 case ALU_XOR: mc = MIPS_XORI; break;
553 case ALU_OR: mc = MIPS_ORI; break;
554 case ALU_AND: mc = MIPS_ANDI; break;
555 default: goto invalid;
557 if (unlikely(imm != (alu == ALU_ADD ? (int64_t)(int16_t)imm : (int64_t)(uint16_t)imm)))
558 internal(file_line, "cgen_alu: invalid imm: %"PRIxMAX" (%u)", (uintmax_t)imm, alu);
559 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
564 case ALU_ADD: if (trap) mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
565 else mc = size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU;
567 case ALU_SUB: if (trap) mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
568 else mc = size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU;
570 case ALU_XOR: mc = MIPS_XOR; break;
571 case ALU_OR: mc = MIPS_OR; break;
572 case ALU_AND: mc = MIPS_AND; break;
573 default: goto invalid;
575 cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
579 internal(file_line, "cgen_alu: invalid alu %u, %u, %"PRIxMAX"", size, alu, (uintmax_t)imm);
583 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
585 bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
586 int cnst = alu == ALU1_INC ? 1 : alu == ALU1_DEC ? -1 : 0;
587 uint8_t *arg1 = ctx->code_position;
588 uint8_t *arg2 = arg1 + arg_size(*arg1);
589 ctx->code_position = arg2 + arg_size(*arg2);
591 if (cnst && trap && !have_imm_trap) {
592 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
593 g(cgen_trap(ctx, cget_four(ctx)));
594 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD, arg1[0], arg2[0], R_AT);
597 if (MIPS_R4000_ERRATA && cnst && !trap && size == OP_SIZE_8) { /* R4000 has broken DADDIU */
598 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
599 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, arg1[0], arg2[0], R_AT);
604 g(cgen_trap(ctx, cget_four(ctx)));
607 case ALU1_NOT: cgen_mips_3reg(MIPS_NOR, arg1[0], R_ZERO, arg2[0]);
609 case ALU1_NEG: if (trap) cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB, arg1[0], R_ZERO, arg2[0]);
610 else cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, arg1[0], R_ZERO, arg2[0]);
613 case ALU1_DEC: if (trap) cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI, arg1[0], arg2[0], cnst);
614 else cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, arg1[0], arg2[0], cnst);
616 case ALU1_LZCNT: if (!MIPS_R6)
617 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DCLZ : MIPS_CLZ, arg1[0], arg2[0], arg1[0]);
619 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DCLZ : MIPS_R6_CLZ, arg1[0], arg2[0], 0);
622 bswap: if (size == OP_SIZE_4) {
623 cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
624 cgen_mips_rot_imm(MIPS_ROTR, arg1[0], arg1[0], 16);
626 cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
627 cgen_mips_3reg(MIPS_DSHD, arg1[0], 0, arg1[0]);
630 case ALU1_BSWAP16:if (size == OP_SIZE_4) {
631 cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
633 cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
636 case ALU1_BREV: cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DBITSWAP : MIPS_R6_BITSWAP, arg1[0], 0, arg2[0]);
639 default: goto invalid;
643 internal(file_line, "cgen_alu1: invalid alu %u, %u", size, alu);
647 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
650 uint8_t *arg1 = ctx->code_position;
651 uint8_t *arg2 = arg1 + arg_size(*arg1);
652 uint8_t *arg3 = arg2 + arg_size(*arg2);
653 ctx->code_position = arg3 + arg_size(*arg3);
655 if (arg3[0] == ARG_IMM) {
656 int64_t imm = get_imm(&arg3[1]);
658 case ROT_SHL: mc = size == OP_SIZE_4 ? MIPS_SLL : imm & 0x20 ? MIPS_DSLL32 : MIPS_DSLL; break;
659 case ROT_SHR: mc = size == OP_SIZE_4 ? MIPS_SRL : imm & 0x20 ? MIPS_DSRL32 : MIPS_DSRL; break;
660 case ROT_SAR: mc = size == OP_SIZE_4 ? MIPS_SRA : imm & 0x20 ? MIPS_DSRA32 : MIPS_DSRA; break;
661 case ROT_ROR: mc = size == OP_SIZE_4 ? MIPS_ROTR : imm & 0x20 ? MIPS_DROTR32 : MIPS_DROTR; break;
662 default: goto invalid;
664 cgen_mips_rot_imm(mc, arg1[0], arg2[0], imm);
668 case ROT_SHL: mc = size == OP_SIZE_4 ? MIPS_SLLV : MIPS_DSLLV; break;
669 case ROT_SHR: mc = size == OP_SIZE_4 ? MIPS_SRLV : MIPS_DSRLV; break;
670 case ROT_SAR: mc = size == OP_SIZE_4 ? MIPS_SRAV : MIPS_DSRAV; break;
671 case ROT_ROR: mc = size == OP_SIZE_4 ? MIPS_ROTRV : MIPS_DROTRV; break;
672 default: goto invalid;
674 cgen_mips_3reg(mc, arg1[0], arg3[0], arg2[0]);
679 internal(file_line, "cgen_rot: invalid rotation %u, %u", size, alu);
683 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size)
685 uint8_t *arg1, *arg2, *arg3, *arg4;
686 arg1 = ctx->code_position;
687 arg2 = arg1 + arg_size(*arg1);
688 arg3 = arg2 + arg_size(*arg2);
689 arg4 = arg3 + arg_size(*arg3);
690 ctx->code_position = arg4 + arg_size(*arg4);
692 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg3[0], arg4[0]);
693 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
694 cgen_mips_3reg(MIPS_MFHI, arg2[0], 0, 0);
699 static bool fp_condition_negated(unsigned aux)
702 case FP_COND_P: return false;
703 case FP_COND_E: return false;
704 case FP_COND_B: return false;
705 case FP_COND_BE: return false;
706 case FP_COND_NP: return true;
707 case FP_COND_NE: return true;
708 case FP_COND_AE: return true;
709 case FP_COND_A: return true;
710 default: internal(file_line, "fp_condition_negated: invalid condition %u", aux);
715 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
718 uint8_t *arg1 = ctx->code_position;
719 uint8_t *arg2 = arg1 + arg_size(*arg1);
720 ctx->code_position = arg2 + arg_size(*arg2);
724 case FP_COND_P: mc = MIPS_R6_CMP_UN; break;
725 case FP_COND_E: mc = MIPS_R6_CMP_EQ; break;
726 case FP_COND_B: mc = MIPS_R6_CMP_LT; break;
727 case FP_COND_BE: mc = MIPS_R6_CMP_LE; break;
728 case FP_COND_NP: mc = MIPS_R6_CMP_UN; break;
729 case FP_COND_NE: mc = MIPS_R6_CMP_EQ; break;
730 case FP_COND_AE: mc = MIPS_R6_CMP_LT; break;
731 case FP_COND_A: mc = MIPS_R6_CMP_LE; break;
732 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
737 case FP_COND_P: mc = MIPS_C_UN; break;
738 case FP_COND_E: mc = MIPS_C_EQ; break;
739 case FP_COND_B: mc = MIPS_C_OLT; break;
740 case FP_COND_BE: mc = MIPS_C_OLE; break;
741 case FP_COND_NP: mc = MIPS_C_UN; break;
742 case FP_COND_NE: mc = MIPS_C_EQ; break;
743 case FP_COND_AE: mc = MIPS_C_OLT; break;
744 case FP_COND_A: mc = MIPS_C_OLE; break;
745 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
749 fmt = cgen_fp_fmt(op_size);
750 cgen_mips_fp(mc, fmt, MIPS_R6 ? FR_CMP_RESULT & 31 : 0, arg1[0] & 31, arg2[0] & 31);
751 if (MIPS_FCMP_DELAY_SLOTS)
756 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx, unsigned aux)
758 unsigned reg = cget_one(ctx);
760 cgen_mips_fp(MIPS_MFC1, MIPS_FP_SINGLE, 0, FR_CMP_RESULT & 31, reg);
761 if (OP_SIZE_NATIVE > OP_SIZE_4) {
762 cgen_mips_rot_imm(MIPS_SLL, reg, reg, 0);
764 if (!fp_condition_negated(aux)) {
765 cgen_mips_3reg(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, reg, R_ZERO, reg);
767 cgen_mips_imm(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, reg, reg, 1);
770 } else if (MIPS_HAS_MOVT) {
771 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
772 cgen_mips_3reg(!fp_condition_negated(aux) ? MIPS_MOVF : MIPS_MOVT, reg, R_ZERO, 0);
774 g(cgen_jump_not_last(ctx, 1));
775 cgen_mips_imm(!fp_condition_negated(aux) ? MIPS_BC1T : MIPS_BC1F, 0, 0, 2);
776 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
777 cgen_mips_3reg(MIPS_OR, reg, R_ZERO, R_ZERO);
782 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
785 uint8_t *arg1 = ctx->code_position;
786 uint8_t *arg2 = arg1 + arg_size(*arg1);
787 uint8_t *arg3 = arg2 + arg_size(*arg2);
788 ctx->code_position = arg3 + arg_size(*arg3);
790 case FP_ALU_ADD: mc = MIPS_ADD_FP; break;
791 case FP_ALU_SUB: mc = MIPS_SUB_FP; break;
792 case FP_ALU_MUL: mc = MIPS_MUL_FP; break;
793 case FP_ALU_DIV: mc = MIPS_DIV_FP; break;
794 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
796 fmt = cgen_fp_fmt(op_size);
797 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
801 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
804 uint8_t *arg1 = ctx->code_position;
805 uint8_t *arg2 = arg1 + arg_size(*arg1);
806 ctx->code_position = arg2 + arg_size(*arg2);
808 case FP_ALU1_NEG: mc = MIPS_NEG_FP; break;
809 case FP_ALU1_SQRT: mc = MIPS_SQRT_FP; break;
810 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
812 fmt = cgen_fp_fmt(op_size);
813 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
817 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
820 uint8_t *arg1 = ctx->code_position;
821 uint8_t *arg2 = arg1 + arg_size(*arg1);
822 ctx->code_position = arg2 + arg_size(*arg2);
823 switch (int_op_size) {
824 case OP_SIZE_4: mc = MIPS_TRUNC_W; break;
825 case OP_SIZE_8: mc = MIPS_TRUNC_L; break;
826 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
828 fmt = cgen_fp_fmt(fp_op_size);
829 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
833 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
836 uint8_t *arg1 = ctx->code_position;
837 uint8_t *arg2 = arg1 + arg_size(*arg1);
838 ctx->code_position = arg2 + arg_size(*arg2);
840 if (int_op_size == OP_SIZE_4) {
841 if (fp_op_size == OP_SIZE_4)
846 if (fp_op_size == OP_SIZE_4)
851 cgen_mips_fp(mc, 0, arg1[0] & 31, arg2[0] & 31, 0);
855 static unsigned cgen_jmp_extra_long_length(void)
857 return !MIPS_R6 ? 6 : 5;
860 static bool attr_w cgen_jmp_extra_long(struct codegen_context *ctx)
862 cgen_mips_imm(MIPS_LUI, R_AT, 0, 0);
863 cgen_mips_imm(MIPS_BGEZAL, 0, R_ZERO, 1);
864 cgen_mips_imm(MIPS_ORI, R_AT, R_AT, 0);
865 cgen_mips_3reg(OP_SIZE_ADDRESS == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, R_AT, R_AT, R_RA);
867 cgen_mips_3reg(MIPS_JR, 0, R_AT, 0);
870 cgen_mips_imm(MIPS_R6_JIC, R_AT, 0, 0);
875 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
877 if (MIPS_R6 && length <= JMP_LONG) {
878 g(cgen_jump_not_last(ctx, 1));
879 g(add_relocation(ctx, JMP_LONG, 0, NULL));
880 cgen_four(MIPS_R6_BC);
883 if (length == JMP_SHORTEST) {
884 g(cgen_jump_not_last(ctx, 1));
885 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
886 cgen_mips_imm(MIPS_BEQ, R_ZERO, R_ZERO, 0);
890 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length()));
891 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
892 g(cgen_jmp_extra_long(ctx));
896 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
899 uint8_t *arg1 = ctx->code_position;
900 ctx->code_position = arg1 + arg_size(*arg1);
905 if (MIPS_R6 && (cond == COND_E || cond == COND_NE) && length <= JMP_SHORT) {
906 mc = cond == COND_E ? MIPS_R6_BEQZC : MIPS_R6_BNEZC;
907 g(cgen_jump_not_last(ctx, 1));
908 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
909 cgen_four(mc | ((uint32_t)arg1[0] << 21));
914 if (length > JMP_SHORTEST)
918 case COND_E: mc = MIPS_BEQ; break;
919 case COND_NE: mc = MIPS_BNE; break;
921 case COND_L: mc = MIPS_BLTZ; break;
922 case COND_LE: mc = MIPS_BLEZ; break;
923 case COND_G: mc = MIPS_BGTZ; break;
925 case COND_GE: mc = MIPS_BGEZ; break;
926 default: goto invalid;
929 if (length == JMP_SHORTEST) {
930 g(cgen_jump_not_last(ctx, 1));
931 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
932 cgen_mips_imm(mc, 0, arg1[0], 0);
936 if (MIPS_R6 && length <= JMP_LONG) {
937 g(cgen_jump_not_last(ctx, 3));
938 cgen_mips_imm(mc, 0, arg1[0], 2);
940 g(add_relocation(ctx, JMP_LONG, 1, NULL));
941 cgen_four(MIPS_R6_BC);
944 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
945 cgen_mips_imm(mc, 0, arg1[0], cgen_jmp_extra_long_length());
946 g(add_relocation(ctx, JMP_EXTRA_LONG, 1, NULL));
947 g(cgen_jmp_extra_long(ctx));
951 internal(file_line, "cgen_jmp_reg: invalid arguments %u, %u, %02x", cond, length, arg1[0]);
955 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
958 uint8_t *arg1 = ctx->code_position;
959 uint8_t *arg2 = arg1 + arg_size(*arg1);
960 ctx->code_position = arg2 + arg_size(*arg2);
961 if (arg1[0] >= 0x20 || arg2[0] >= 0x20 || (cond != COND_E && cond != COND_NE))
964 if (length > JMP_SHORTEST)
967 mc = cond == COND_E ? MIPS_BEQ : MIPS_BNE;
969 if (length == JMP_SHORTEST) {
970 g(cgen_jump_not_last(ctx, 1));
971 g(add_relocation(ctx, JMP_SHORTEST, 2, NULL));
972 cgen_mips_imm(mc, arg1[0], arg2[0], 0);
976 if (MIPS_R6 && length <= JMP_LONG) {
977 g(cgen_jump_not_last(ctx, 3));
978 cgen_mips_imm(mc, arg1[0], arg2[0], 2);
980 g(add_relocation(ctx, JMP_LONG, 1, NULL));
981 cgen_four(MIPS_R6_BC);
984 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
985 cgen_mips_imm(mc, arg1[0], arg2[0], cgen_jmp_extra_long_length());
986 g(add_relocation(ctx, JMP_EXTRA_LONG, 2, NULL));
987 g(cgen_jmp_extra_long(ctx));
991 internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
995 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned aux, unsigned length)
999 if (fp_condition_negated(aux))
1001 if (length > JMP_SHORTEST)
1004 mc = t ? MIPS_R6_BC1NEZ : MIPS_R6_BC1EQZ;
1005 if (length == JMP_SHORTEST) {
1006 g(cgen_jump_not_last(ctx, 1));
1007 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1008 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 0);
1009 cgen_four(MIPS_NOP);
1012 if (length <= JMP_LONG) {
1013 g(cgen_jump_not_last(ctx, 3));
1014 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 2);
1015 cgen_four(MIPS_NOP);
1016 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1017 cgen_four(MIPS_R6_BC);
1020 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1021 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, cgen_jmp_extra_long_length());
1022 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1023 g(cgen_jmp_extra_long(ctx));
1026 mc = t ? MIPS_BC1T : MIPS_BC1F;
1027 if (length == JMP_SHORTEST) {
1028 g(cgen_jump_not_last(ctx, 1));
1029 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1030 cgen_mips_imm(mc, 0, 0, 0);
1031 cgen_four(MIPS_NOP);
1034 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1035 cgen_mips_imm(mc, 0, 0, cgen_jmp_extra_long_length());
1036 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1037 g(cgen_jmp_extra_long(ctx));
1042 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, unsigned reg, bool call)
1044 g(cgen_jump_not_last(ctx, 1));
1047 cgen_mips_3reg(MIPS_JR, 0, reg, 0);
1048 cgen_four(MIPS_NOP);
1050 cgen_mips_imm(MIPS_R6_JIC, reg, 0, 0);
1054 cgen_mips_3reg(MIPS_JALR, R_RA, reg, 0);
1055 cgen_four(MIPS_NOP);
1057 cgen_mips_imm(MIPS_R6_JIALC, reg, 0, 0);
1064 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1067 int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1068 switch (reloc->length) {
1072 if (offs != (int16_t)offs)
1074 memcpy(&mc, ctx->mcode + reloc->position, 4);
1076 mc |= offs & 0xFFFFU;
1077 memcpy(ctx->mcode + reloc->position, &mc, 4);
1082 if (offs < -0x00100000 || offs >= 0x00100000)
1084 memcpy(&mc, ctx->mcode + reloc->position, 4);
1086 mc |= offs & 0x001FFFFFU;
1087 memcpy(ctx->mcode + reloc->position, &mc, 4);
1092 if (offs < -0x02000000 || offs >= 0x02000000)
1094 memcpy(&mc, ctx->mcode + reloc->position, 4);
1096 mc |= offs & 0x03FFFFFFU;
1097 memcpy(ctx->mcode + reloc->position, &mc, 4);
1099 case JMP_EXTRA_LONG:
1101 if (offs != (int32_t)offs)
1103 memcpy(&mc, ctx->mcode + reloc->position, 4);
1105 mc |= ((uint64_t)offs >> 16) & 0xFFFFU;
1106 memcpy(ctx->mcode + reloc->position, &mc, 4);
1107 memcpy(&mc, ctx->mcode + reloc->position + 8, 4);
1109 mc |= offs & 0xFFFFU;
1110 memcpy(ctx->mcode + reloc->position + 8, &mc, 4);
1113 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1119 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1121 if (unlikely(insn_writes_flags(insn))) {
1122 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
1125 switch (insn_opcode(insn)) {
1133 g(cgen_jmp_call_indirect(ctx, R_RA, false));
1135 cgen_four(MIPS_NOP);
1137 case INSN_CALL_INDIRECT:
1138 g(cgen_jmp_call_indirect(ctx, cget_one(ctx), true));
1141 g(cgen_mov(ctx, insn_op_size(insn), false));
1144 g(cgen_mov(ctx, insn_op_size(insn), true));
1147 g(cgen_mov_lr(ctx, insn_op_size(insn), insn_aux(insn) != 0));
1149 case INSN_CMP_DEST_REG:
1150 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1152 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
1155 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1157 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), false));
1160 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1162 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), true));
1165 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1167 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
1169 case INSN_ALU1_TRAP:
1170 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1172 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
1175 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1177 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
1180 if (unlikely(insn_op_size(insn) <= OP_SIZE_2) || unlikely(insn_op_size(insn) > OP_SIZE_NATIVE))
1182 g(cgen_mul_l(ctx, insn_op_size(insn)));
1184 case INSN_FP_CMP_COND:
1185 g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
1187 case INSN_FP_TEST_REG:
1188 g(cgen_fp_test_reg(ctx, insn_aux(insn)));
1191 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1194 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1196 case INSN_FP_TO_INT32:
1197 case INSN_FP_TO_INT64:
1198 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1200 case INSN_FP_FROM_INT32:
1201 case INSN_FP_FROM_INT64:
1202 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1205 g(cgen_jmp(ctx, insn_jump_size(insn)));
1208 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1210 case INSN_JMP_2REGS:
1211 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
1213 case INSN_JMP_FP_TEST:
1214 g(cgen_jmp_fp_test(ctx, insn_aux(insn), insn_jump_size(insn)));
1216 case INSN_JMP_INDIRECT:
1217 g(cgen_jmp_call_indirect(ctx, cget_one(ctx), false));
1221 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);