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_BGEUC 0x18000000U
172 #define MIPS_R6_BLTUC 0x1c000000U
173 #define MIPS_R6_AUI 0x3c000000U
174 #define MIPS_R6_BC1EQZ 0x45200000U
175 #define MIPS_R6_BC1NEZ 0x45a00000U
176 #define MIPS_R6_CMP_AF 0x46800000U
177 #define MIPS_R6_CMP_UN 0x46800001U
178 #define MIPS_R6_CMP_EQ 0x46800002U
179 #define MIPS_R6_CMP_UEQ 0x46800003U
180 #define MIPS_R6_CMP_LT 0x46800004U
181 #define MIPS_R6_CMP_ULT 0x46800005U
182 #define MIPS_R6_CMP_LE 0x46800006U
183 #define MIPS_R6_CMP_ULE 0x46800007U
184 #define MIPS_R6_CMP_OR 0x46800011U
185 #define MIPS_R6_CMP_UNE 0x46800012U
186 #define MIPS_R6_CMP_NE 0x46800013U
187 #define MIPS_R6_BGEC 0x58000000U
188 #define MIPS_R6_BLTC 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
197 #define MIPS_R6_BLTC 0x5c000000U
198 #define MIPS_R6_BGEC 0x58000000U
200 #define cgen_mips_3reg(mc, rd, rs, rt) \
201 cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rs) << 21) | ((uint32_t)(rt) << 16))
202 #define cgen_mips_rot_imm(mc, rd, rt, sa) \
203 cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rt) << 16) | (((sa) & 0x1f) << 6))
204 #define cgen_mips_imm(mc, rt, rs, imm) \
205 cgen_four((mc) | ((uint32_t)(rt) << 16) | ((uint32_t)(rs) << 21) | ((imm) & 0xffff))
206 #define cgen_mips_fp(mc, fmt, fd, fs, ft) \
207 cgen_four((mc) | ((uint32_t)(fmt) << 21) | ((uint32_t)(fd) << 6) | ((uint32_t)(fs) << 11) | ((uint32_t)(ft) << 16))
209 static bool attr_w cgen_jump_not_last(struct codegen_context *ctx, unsigned insns)
211 if (MIPS_R4000_ERRATA) {
212 while (unlikely((ctx->mcode_size & 0xfffU) + insns * 4 >= 0x1000U)) {
219 static bool attr_w cgen_ls(struct codegen_context *ctx, uint32_t mc, uint8_t arg1, uint8_t *arg2)
221 int64_t imm = get_imm(&arg2[2]);
222 if (unlikely(imm != (int16_t)imm))
223 internal(file_line, "cgen_ls: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
224 cgen_mips_imm(mc, arg1, arg2[1], imm);
228 static uint32_t cgen_fp_fmt(unsigned op_size)
231 case OP_SIZE_4: return MIPS_FP_SINGLE;
232 case OP_SIZE_8: return MIPS_FP_DOUBLE;
233 default: internal(file_line, "cgen_fp_fmt: invalid size %u", op_size);
238 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
242 uint8_t *arg1 = ctx->code_position;
243 uint8_t *arg2 = arg1 + arg_size(*arg1);
244 ctx->code_position = arg2 + arg_size(*arg2);
247 if (sx && size == OP_SIZE_1) {
248 cgen_mips_3reg(MIPS_SEB, arg1[0], 0, arg2[0]);
251 if (sx && size == OP_SIZE_2) {
252 cgen_mips_3reg(MIPS_SEH, arg1[0], 0, arg2[0]);
255 if (unlikely(size != OP_SIZE_NATIVE))
256 internal(file_line, "cgen_mov: unsupported size %u", size);
257 cgen_mips_3reg(MIPS_OR, arg1[0], arg2[0], R_ZERO);
260 if (reg_is_fp(arg2[0])) {
261 uint32_t fmt = cgen_fp_fmt(size);
262 cgen_mips_fp(MIPS_MFC1, fmt, 0, arg2[0] & 31, arg1[0]);
265 if (arg2[0] == ARG_IMM) {
266 imm = get_imm(&arg2[1]);
267 if (unlikely((imm & 0xffff) != 0) || unlikely(imm != (int32_t)imm))
268 internal(file_line, "cgen_mov: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
269 cgen_mips_imm(MIPS_LUI, arg1[0], 0, (uint64_t)imm >> 16);
272 if (arg2[0] == ARG_ADDRESS_1) {
273 if (!sx && size != OP_SIZE_NATIVE)
274 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LBU : size == OP_SIZE_2 ? MIPS_LHU : MIPS_LWU, arg1[0], arg2));
276 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));
277 if (MIPS_LOAD_DELAY_SLOTS)
283 if (reg_is_fp(arg1[0])) {
285 uint32_t fmt = cgen_fp_fmt(size);
286 cgen_mips_fp(MIPS_MTC1, fmt, 0, arg1[0] & 31, arg2[0]);
289 if (reg_is_fp(arg2[0])) {
290 uint32_t fmt = cgen_fp_fmt(size);
291 uint32_t mc = MIPS_MOV_FP;
292 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
295 g(cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_LWC1 : MIPS_LDC1, arg1[0] & 31, arg2));
296 if (MIPS_LOAD_DELAY_SLOTS)
300 if (arg1[0] == ARG_ADDRESS_1) {
301 if (arg2[0] == ARG_IMM) {
302 imm = get_imm(&arg2[1]);
303 if (unlikely(imm != 0))
308 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);
310 if (reg_is_fp(arg2[0])) {
311 return cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_SWC1 : MIPS_SDC1, arg2[0] & 31, arg1);
317 internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u, %u", arg1[0], arg2[0], size, (unsigned)sx);
321 static bool attr_w cgen_mov_lr(struct codegen_context *ctx, unsigned size, bool r)
325 uint8_t *arg1, *arg2, *arg3;
326 arg1 = ctx->code_position;
327 arg2 = arg1 + arg_size(*arg1);
328 arg3 = arg2 + arg_size(*arg2);
329 ctx->code_position = arg3 + arg_size(*arg3);
331 if (unlikely(arg1[0] != arg2[0]))
334 if (arg1[0] < 32 && arg3[0] == ARG_ADDRESS_1) {
335 imm = get_imm(&arg3[2]);
337 mc = size == OP_SIZE_4 ? MIPS_LWL : MIPS_LDL;
339 mc = size == OP_SIZE_4 ? MIPS_LWR : MIPS_LDR;
340 cgen_mips_imm(mc, arg1[0], arg3[1], imm);
341 if (MIPS_LOAD_DELAY_SLOTS)
344 } if (arg1[0] == ARG_ADDRESS_1 && arg3[0] < 32) {
345 imm = get_imm(&arg1[2]);
347 mc = size == OP_SIZE_4 ? MIPS_SWL : MIPS_SDL;
349 mc = size == OP_SIZE_4 ? MIPS_SWR : MIPS_SDR;
350 cgen_mips_imm(mc, arg3[0], arg1[1], imm);
355 internal(file_line, "cgen_mov_lr: invalid parameters %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
359 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
364 uint8_t *arg1 = ctx->code_position;
365 uint8_t *arg2 = arg1 + arg_size(*arg1);
366 uint8_t *arg3 = arg2 + arg_size(*arg2);
367 ctx->code_position = arg3 + arg_size(*arg3);
368 if (arg3[0] == ARG_IMM) {
369 int64_t imm = get_imm(&arg3[1]);
370 if (unlikely(imm != (int16_t)imm))
371 internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
373 case COND_B: mc = MIPS_SLTIU; break;
374 case COND_L: mc = MIPS_SLTI; break;
375 default: goto invalid;
377 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
380 if (arg2[0] == ARG_IMM) {
381 int64_t imm = get_imm(&arg2[1]);
382 if (unlikely(imm != 0))
383 internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
387 case COND_B: mc = MIPS_SLTU; break;
388 case COND_A: mc = MIPS_SLTU; swap = true; break;
389 case COND_L: mc = MIPS_SLT; break;
390 case COND_G: mc = MIPS_SLT; swap = true; break;
391 default: goto invalid;
394 uint8_t *argx = arg2;
398 cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
402 internal(file_line, "cgen_cmp_dest_reg: invalid arguments %u, %02x, %02x, %02x", aux, arg1[0], arg2[0], arg3[0]);
406 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
410 bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
411 uint8_t *arg1 = ctx->code_position;
412 uint8_t *arg2 = arg1 + arg_size(*arg1);
413 uint8_t *arg3 = arg2 + arg_size(*arg2);
414 ctx->code_position = arg3 + arg_size(*arg3);
416 if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
417 uint8_t *arg_swp = arg3;
421 if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
423 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL))
425 shift = arg3[1] & ARG_SHIFT_AMOUNT;
426 if (unlikely(shift < 1) || unlikely(shift > 4))
428 mc = size == OP_SIZE_8 ? MIPS_R6_DLSA : MIPS_R6_LSA;
429 mc |= (shift - 1) << 6;
430 cgen_mips_3reg(mc, arg1[0], arg3[2], arg2[0]);
434 if ((alu == ALU_ADD || alu == ALU_SUB) && arg3[0] == ARG_IMM && trap && !have_imm_trap) {
435 imm = get_imm(&arg3[1]);
436 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, imm);
437 g(cgen_trap(ctx, cget_four(ctx)));
439 mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
441 mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
442 cgen_mips_3reg(mc, arg1[0], arg2[0], R_AT);
445 if (MIPS_R6 && alu == ALU_ADD && arg3[0] == ARG_IMM && !trap) {
446 imm = get_imm(&arg3[1]);
447 if (imm && !(imm & 0xffff)) {
448 if (imm == (int32_t)imm) {
449 cgen_mips_imm(size == OP_SIZE_4 ? MIPS_R6_AUI : MIPS_R6_DAUI, arg1[0], arg2[0], (uint64_t)imm >> 16);
452 if (imm & 0xFFFFFFFFLL)
454 imm /= 0x100000000LL;
455 if (imm == (int16_t)imm && size == OP_SIZE_8) {
456 if (unlikely(arg1[0] != arg2[0]))
458 cgen_mips_imm(MIPS_R6_DAHI, 0, arg1[0], imm);
464 if (size == OP_SIZE_8) {
465 if (unlikely(arg1[0] != arg2[0]))
467 cgen_mips_imm(MIPS_R6_DATI, 0, arg1[0], imm);
475 g(cgen_trap(ctx, cget_four(ctx)));
480 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUL : MIPS_R6_DMUL, arg1[0], arg2[0], arg3[0]);
483 if (size == OP_SIZE_4 && MIPS_HAS_MUL) {
484 cgen_mips_3reg(MIPS_MUL, arg1[0], arg2[0], arg3[0]);
487 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
488 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
492 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUHU : MIPS_R6_DMUHU, arg1[0], arg2[0], arg3[0]);
495 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
496 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
500 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUH : MIPS_R6_DMUH, arg1[0], arg2[0], arg3[0]);
503 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg2[0], arg3[0]);
504 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
508 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIVU : MIPS_R6_DDIVU, arg1[0], arg2[0], arg3[0]);
511 g(cgen_jump_not_last(ctx, 1));
512 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
513 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
517 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIV : MIPS_R6_DDIV, arg1[0], arg2[0], arg3[0]);
520 g(cgen_jump_not_last(ctx, 1));
521 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
522 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
526 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MODU : MIPS_R6_DMODU, arg1[0], arg2[0], arg3[0]);
529 g(cgen_jump_not_last(ctx, 1));
530 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
531 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
535 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MOD : MIPS_R6_DMOD, arg1[0], arg2[0], arg3[0]);
538 g(cgen_jump_not_last(ctx, 1));
539 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
540 cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
544 if (arg3[0] == ARG_IMM) {
545 imm = get_imm(&arg3[1]);
546 if (alu == ALU_SUB) {
547 imm = -(uint64_t)imm;
551 case ALU_ADD: if (trap) mc = size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI;
552 else mc = size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU;
554 case ALU_XOR: mc = MIPS_XORI; break;
555 case ALU_OR: mc = MIPS_ORI; break;
556 case ALU_AND: mc = MIPS_ANDI; break;
557 default: goto invalid;
559 if (unlikely(imm != (alu == ALU_ADD ? (int64_t)(int16_t)imm : (int64_t)(uint16_t)imm)))
560 internal(file_line, "cgen_alu: invalid imm: %"PRIxMAX" (%u)", (uintmax_t)imm, alu);
561 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
566 case ALU_ADD: if (trap) mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
567 else mc = size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU;
569 case ALU_SUB: if (trap) mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
570 else mc = size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU;
572 case ALU_XOR: mc = MIPS_XOR; break;
573 case ALU_OR: mc = MIPS_OR; break;
574 case ALU_AND: mc = MIPS_AND; break;
575 default: goto invalid;
577 cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
581 internal(file_line, "cgen_alu: invalid alu %u, %u, %"PRIxMAX"", size, alu, (uintmax_t)imm);
585 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
587 uint8_t *arg1 = ctx->code_position;
588 uint8_t *arg2 = arg1 + arg_size(*arg1);
589 ctx->code_position = arg2 + arg_size(*arg2);
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]);
600 case ALU1_LZCNT: if (!MIPS_R6)
601 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DCLZ : MIPS_CLZ, arg1[0], arg2[0], arg1[0]);
603 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DCLZ : MIPS_R6_CLZ, arg1[0], arg2[0], 0);
606 bswap: if (size == OP_SIZE_4) {
607 cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
608 cgen_mips_rot_imm(MIPS_ROTR, arg1[0], arg1[0], 16);
610 cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
611 cgen_mips_3reg(MIPS_DSHD, arg1[0], 0, arg1[0]);
614 case ALU1_BSWAP16:if (size == OP_SIZE_4) {
615 cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
617 cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
620 case ALU1_BREV: cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DBITSWAP : MIPS_R6_BITSWAP, arg1[0], 0, arg2[0]);
623 default: goto invalid;
627 internal(file_line, "cgen_alu1: invalid alu %u, %u", size, alu);
631 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
634 uint8_t *arg1 = ctx->code_position;
635 uint8_t *arg2 = arg1 + arg_size(*arg1);
636 uint8_t *arg3 = arg2 + arg_size(*arg2);
637 ctx->code_position = arg3 + arg_size(*arg3);
639 if (arg3[0] == ARG_IMM) {
640 int64_t imm = get_imm(&arg3[1]);
642 case ROT_SHL: mc = size == OP_SIZE_4 ? MIPS_SLL : imm & 0x20 ? MIPS_DSLL32 : MIPS_DSLL; break;
643 case ROT_SHR: mc = size == OP_SIZE_4 ? MIPS_SRL : imm & 0x20 ? MIPS_DSRL32 : MIPS_DSRL; break;
644 case ROT_SAR: mc = size == OP_SIZE_4 ? MIPS_SRA : imm & 0x20 ? MIPS_DSRA32 : MIPS_DSRA; break;
645 case ROT_ROR: mc = size == OP_SIZE_4 ? MIPS_ROTR : imm & 0x20 ? MIPS_DROTR32 : MIPS_DROTR; break;
646 default: goto invalid;
648 cgen_mips_rot_imm(mc, arg1[0], arg2[0], imm);
652 case ROT_SHL: mc = size == OP_SIZE_4 ? MIPS_SLLV : MIPS_DSLLV; break;
653 case ROT_SHR: mc = size == OP_SIZE_4 ? MIPS_SRLV : MIPS_DSRLV; break;
654 case ROT_SAR: mc = size == OP_SIZE_4 ? MIPS_SRAV : MIPS_DSRAV; break;
655 case ROT_ROR: mc = size == OP_SIZE_4 ? MIPS_ROTRV : MIPS_DROTRV; break;
656 default: goto invalid;
658 cgen_mips_3reg(mc, arg1[0], arg3[0], arg2[0]);
663 internal(file_line, "cgen_rot: invalid rotation %u, %u", size, alu);
667 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size)
669 uint8_t *arg1, *arg2, *arg3, *arg4;
670 arg1 = ctx->code_position;
671 arg2 = arg1 + arg_size(*arg1);
672 arg3 = arg2 + arg_size(*arg2);
673 arg4 = arg3 + arg_size(*arg3);
674 ctx->code_position = arg4 + arg_size(*arg4);
676 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg3[0], arg4[0]);
677 cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
678 cgen_mips_3reg(MIPS_MFHI, arg2[0], 0, 0);
683 static bool fp_condition_negated(unsigned aux)
686 case FP_COND_P: return false;
687 case FP_COND_E: return false;
688 case FP_COND_B: return false;
689 case FP_COND_BE: return false;
690 case FP_COND_NP: return true;
691 case FP_COND_NE: return true;
692 case FP_COND_AE: return true;
693 case FP_COND_A: return true;
694 default: internal(file_line, "fp_condition_negated: invalid condition %u", aux);
699 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
702 uint8_t *arg1 = ctx->code_position;
703 uint8_t *arg2 = arg1 + arg_size(*arg1);
704 ctx->code_position = arg2 + arg_size(*arg2);
708 case FP_COND_P: mc = MIPS_R6_CMP_UN; break;
709 case FP_COND_E: mc = MIPS_R6_CMP_EQ; break;
710 case FP_COND_B: mc = MIPS_R6_CMP_LT; break;
711 case FP_COND_BE: mc = MIPS_R6_CMP_LE; break;
712 case FP_COND_NP: mc = MIPS_R6_CMP_UN; break;
713 case FP_COND_NE: mc = MIPS_R6_CMP_EQ; break;
714 case FP_COND_AE: mc = MIPS_R6_CMP_LT; break;
715 case FP_COND_A: mc = MIPS_R6_CMP_LE; break;
716 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
721 case FP_COND_P: mc = MIPS_C_UN; break;
722 case FP_COND_E: mc = MIPS_C_EQ; break;
723 case FP_COND_B: mc = MIPS_C_OLT; break;
724 case FP_COND_BE: mc = MIPS_C_OLE; break;
725 case FP_COND_NP: mc = MIPS_C_UN; break;
726 case FP_COND_NE: mc = MIPS_C_EQ; break;
727 case FP_COND_AE: mc = MIPS_C_OLT; break;
728 case FP_COND_A: mc = MIPS_C_OLE; break;
729 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
733 fmt = cgen_fp_fmt(op_size);
734 cgen_mips_fp(mc, fmt, MIPS_R6 ? FR_CMP_RESULT & 31 : 0, arg1[0] & 31, arg2[0] & 31);
735 if (MIPS_FCMP_DELAY_SLOTS)
740 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx, unsigned aux)
742 unsigned reg = cget_one(ctx);
744 cgen_mips_fp(MIPS_MFC1, MIPS_FP_SINGLE, 0, FR_CMP_RESULT & 31, reg);
745 if (OP_SIZE_NATIVE > OP_SIZE_4) {
746 cgen_mips_rot_imm(MIPS_SLL, reg, reg, 0);
748 if (!fp_condition_negated(aux)) {
749 cgen_mips_3reg(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, reg, R_ZERO, reg);
751 cgen_mips_imm(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, reg, reg, 1);
754 } else if (MIPS_HAS_MOVT) {
755 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
756 cgen_mips_3reg(!fp_condition_negated(aux) ? MIPS_MOVF : MIPS_MOVT, reg, R_ZERO, 0);
758 g(cgen_jump_not_last(ctx, 1));
759 cgen_mips_imm(!fp_condition_negated(aux) ? MIPS_BC1T : MIPS_BC1F, 0, 0, 2);
760 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
761 cgen_mips_3reg(MIPS_OR, reg, R_ZERO, R_ZERO);
766 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
769 uint8_t *arg1 = ctx->code_position;
770 uint8_t *arg2 = arg1 + arg_size(*arg1);
771 uint8_t *arg3 = arg2 + arg_size(*arg2);
772 ctx->code_position = arg3 + arg_size(*arg3);
774 case FP_ALU_ADD: mc = MIPS_ADD_FP; break;
775 case FP_ALU_SUB: mc = MIPS_SUB_FP; break;
776 case FP_ALU_MUL: mc = MIPS_MUL_FP; break;
777 case FP_ALU_DIV: mc = MIPS_DIV_FP; break;
778 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
780 fmt = cgen_fp_fmt(op_size);
781 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
785 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
788 uint8_t *arg1 = ctx->code_position;
789 uint8_t *arg2 = arg1 + arg_size(*arg1);
790 ctx->code_position = arg2 + arg_size(*arg2);
792 case FP_ALU1_NEG: mc = MIPS_NEG_FP; break;
793 case FP_ALU1_SQRT: mc = MIPS_SQRT_FP; break;
794 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
796 fmt = cgen_fp_fmt(op_size);
797 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
801 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
804 uint8_t *arg1 = ctx->code_position;
805 uint8_t *arg2 = arg1 + arg_size(*arg1);
806 ctx->code_position = arg2 + arg_size(*arg2);
807 switch (int_op_size) {
808 case OP_SIZE_4: mc = MIPS_TRUNC_W; break;
809 case OP_SIZE_8: mc = MIPS_TRUNC_L; break;
810 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
812 fmt = cgen_fp_fmt(fp_op_size);
813 cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
817 static bool attr_w cgen_fp_from_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);
824 if (int_op_size == OP_SIZE_4) {
825 if (fp_op_size == OP_SIZE_4)
830 if (fp_op_size == OP_SIZE_4)
835 cgen_mips_fp(mc, 0, arg1[0] & 31, arg2[0] & 31, 0);
839 static unsigned cgen_jmp_extra_long_length(void)
841 return !MIPS_R6 ? 6 : 5;
844 static bool attr_w cgen_jmp_extra_long(struct codegen_context *ctx)
846 cgen_mips_imm(MIPS_LUI, R_AT, 0, 0);
847 cgen_mips_imm(MIPS_BGEZAL, 0, R_ZERO, 1);
848 cgen_mips_imm(MIPS_ORI, R_AT, R_AT, 0);
849 cgen_mips_3reg(OP_SIZE_ADDRESS == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, R_AT, R_AT, R_RA);
851 cgen_mips_3reg(MIPS_JR, 0, R_AT, 0);
854 cgen_mips_imm(MIPS_R6_JIC, R_AT, 0, 0);
859 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
861 if (MIPS_R6 && length <= JMP_LONG) {
862 g(cgen_jump_not_last(ctx, 1));
863 g(add_relocation(ctx, JMP_LONG, 0, NULL));
864 cgen_four(MIPS_R6_BC);
867 if (length == JMP_SHORTEST) {
868 g(cgen_jump_not_last(ctx, 1));
869 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
870 cgen_mips_imm(MIPS_BEQ, R_ZERO, R_ZERO, 0);
874 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length()));
875 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
876 g(cgen_jmp_extra_long(ctx));
880 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
883 uint8_t *arg1 = ctx->code_position;
884 ctx->code_position = arg1 + arg_size(*arg1);
889 if (MIPS_R6 && (cond == COND_E || cond == COND_NE) && length <= JMP_SHORT) {
890 mc = cond == COND_E ? MIPS_R6_BEQZC : MIPS_R6_BNEZC;
891 g(cgen_jump_not_last(ctx, 1));
892 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
893 cgen_four(mc | ((uint32_t)arg1[0] << 21));
898 if (length > JMP_SHORTEST)
902 case COND_E: mc = MIPS_BEQ; break;
903 case COND_NE: mc = MIPS_BNE; break;
905 case COND_L: mc = MIPS_BLTZ; break;
906 case COND_LE: mc = MIPS_BLEZ; break;
907 case COND_G: mc = MIPS_BGTZ; break;
909 case COND_GE: mc = MIPS_BGEZ; break;
910 default: goto invalid;
913 if (length == JMP_SHORTEST) {
914 g(cgen_jump_not_last(ctx, 1));
915 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
916 cgen_mips_imm(mc, 0, arg1[0], 0);
920 if (MIPS_R6 && length <= JMP_LONG) {
921 g(cgen_jump_not_last(ctx, 3));
922 cgen_mips_imm(mc, 0, arg1[0], 2);
924 g(add_relocation(ctx, JMP_LONG, 1, NULL));
925 cgen_four(MIPS_R6_BC);
928 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
929 cgen_mips_imm(mc, 0, arg1[0], cgen_jmp_extra_long_length());
930 g(add_relocation(ctx, JMP_EXTRA_LONG, 1, NULL));
931 g(cgen_jmp_extra_long(ctx));
935 internal(file_line, "cgen_jmp_reg: invalid arguments %u, %u, %02x", cond, length, arg1[0]);
939 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
942 uint8_t *arg1 = ctx->code_position;
943 uint8_t *arg2 = arg1 + arg_size(*arg1);
944 ctx->code_position = arg2 + arg_size(*arg2);
945 if (arg1[0] >= 0x20 || arg2[0] >= 0x20 || (cond != COND_E && cond != COND_NE))
948 if (length > JMP_SHORTEST)
951 mc = cond == COND_E ? MIPS_BEQ : MIPS_BNE;
953 if (length == JMP_SHORTEST) {
954 g(cgen_jump_not_last(ctx, 1));
955 g(add_relocation(ctx, JMP_SHORTEST, 2, NULL));
956 cgen_mips_imm(mc, arg1[0], arg2[0], 0);
960 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
961 cgen_mips_imm(mc, arg1[0], arg2[0], cgen_jmp_extra_long_length());
962 g(add_relocation(ctx, JMP_EXTRA_LONG, 2, NULL));
963 g(cgen_jmp_extra_long(ctx));
967 internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
971 static bool attr_w cgen_jmp_2regs_mips_r6(struct codegen_context *ctx, unsigned cond, unsigned length)
975 uint8_t *arg1 = ctx->code_position;
976 uint8_t *arg2 = arg1 + arg_size(*arg1);
977 uint8_t arg3[1] = { R_AT };
978 ctx->code_position = arg2 + arg_size(*arg2);
979 if (arg1[0] >= 0x20 || arg2[0] >= 0x20)
982 if (arg1[0] == arg2[0]) {
983 cgen_mips_3reg(MIPS_OR, R_AT, arg2[0], R_ZERO);
987 if (length > JMP_SHORTEST)
991 case COND_B: mc = MIPS_R6_BLTUC; break;
992 case COND_AE: mc = MIPS_R6_BGEUC; break;
993 case COND_E: mc = MIPS_BEQ; break;
994 case COND_NE: mc = MIPS_BNE; break;
995 case COND_BE: mc = MIPS_R6_BGEUC; swap = true; break;
996 case COND_A: mc = MIPS_R6_BLTUC; swap = true; break;
998 case COND_L: mc = MIPS_R6_BLTC; break;
1000 case COND_GE: mc = MIPS_R6_BGEC; break;
1001 case COND_LE: mc = MIPS_R6_BGEC; swap = true; break;
1002 case COND_G: mc = MIPS_R6_BLTC; swap = true; break;
1003 default: goto invalid;
1006 uint8_t *argx = arg1;
1011 if (length == JMP_SHORTEST) {
1012 g(add_relocation(ctx, JMP_SHORTEST, 2, NULL));
1013 cgen_mips_imm(mc, arg1[0], arg2[0], 0);
1014 cgen_four(MIPS_NOP);
1017 if (length <= JMP_LONG) {
1018 cgen_mips_imm(mc, arg1[0], arg2[0], 2);
1019 cgen_four(MIPS_NOP);
1020 g(add_relocation(ctx, JMP_LONG, 2, NULL));
1021 cgen_four(MIPS_R6_BC);
1024 cgen_mips_imm(mc, arg1[0], arg2[0], cgen_jmp_extra_long_length());
1025 g(add_relocation(ctx, JMP_EXTRA_LONG, 2, NULL));
1026 g(cgen_jmp_extra_long(ctx));
1030 internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
1034 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned aux, unsigned length)
1038 if (fp_condition_negated(aux))
1040 if (length > JMP_SHORTEST)
1043 mc = t ? MIPS_R6_BC1NEZ : MIPS_R6_BC1EQZ;
1044 if (length == JMP_SHORTEST) {
1045 g(cgen_jump_not_last(ctx, 1));
1046 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1047 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 0);
1048 cgen_four(MIPS_NOP);
1051 if (length <= JMP_LONG) {
1052 g(cgen_jump_not_last(ctx, 3));
1053 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 2);
1054 cgen_four(MIPS_NOP);
1055 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1056 cgen_four(MIPS_R6_BC);
1059 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1060 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, cgen_jmp_extra_long_length());
1061 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1062 g(cgen_jmp_extra_long(ctx));
1065 mc = t ? MIPS_BC1T : MIPS_BC1F;
1066 if (length == JMP_SHORTEST) {
1067 g(cgen_jump_not_last(ctx, 1));
1068 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1069 cgen_mips_imm(mc, 0, 0, 0);
1070 cgen_four(MIPS_NOP);
1073 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1074 cgen_mips_imm(mc, 0, 0, cgen_jmp_extra_long_length());
1075 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1076 g(cgen_jmp_extra_long(ctx));
1081 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, unsigned reg, bool call)
1083 g(cgen_jump_not_last(ctx, 1));
1086 cgen_mips_3reg(MIPS_JR, 0, reg, 0);
1087 cgen_four(MIPS_NOP);
1089 cgen_mips_imm(MIPS_R6_JIC, reg, 0, 0);
1093 cgen_mips_3reg(MIPS_JALR, R_RA, reg, 0);
1094 cgen_four(MIPS_NOP);
1096 cgen_mips_imm(MIPS_R6_JIALC, reg, 0, 0);
1103 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1106 int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1107 switch (reloc->length) {
1111 if (offs != (int16_t)offs)
1113 memcpy(&mc, ctx->mcode + reloc->position, 4);
1115 mc |= offs & 0xFFFFU;
1116 memcpy(ctx->mcode + reloc->position, &mc, 4);
1121 if (offs < -0x00100000 || offs >= 0x00100000)
1123 memcpy(&mc, ctx->mcode + reloc->position, 4);
1125 mc |= offs & 0x001FFFFFU;
1126 memcpy(ctx->mcode + reloc->position, &mc, 4);
1131 if (offs < -0x02000000 || offs >= 0x02000000)
1133 memcpy(&mc, ctx->mcode + reloc->position, 4);
1135 mc |= offs & 0x03FFFFFFU;
1136 memcpy(ctx->mcode + reloc->position, &mc, 4);
1138 case JMP_EXTRA_LONG:
1140 if (offs != (int32_t)offs)
1142 memcpy(&mc, ctx->mcode + reloc->position, 4);
1144 mc |= ((uint64_t)offs >> 16) & 0xFFFFU;
1145 memcpy(ctx->mcode + reloc->position, &mc, 4);
1146 memcpy(&mc, ctx->mcode + reloc->position + 8, 4);
1148 mc |= offs & 0xFFFFU;
1149 memcpy(ctx->mcode + reloc->position + 8, &mc, 4);
1152 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1158 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1160 if (unlikely(insn_writes_flags(insn))) {
1161 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
1164 switch (insn_opcode(insn)) {
1172 g(cgen_jmp_call_indirect(ctx, R_RA, false));
1174 cgen_four(MIPS_NOP);
1176 case INSN_CALL_INDIRECT:
1177 g(cgen_jmp_call_indirect(ctx, cget_one(ctx), true));
1180 g(cgen_mov(ctx, insn_op_size(insn), false));
1183 g(cgen_mov(ctx, insn_op_size(insn), true));
1186 g(cgen_mov_lr(ctx, insn_op_size(insn), insn_aux(insn) != 0));
1188 case INSN_CMP_DEST_REG:
1189 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1191 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
1194 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1196 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), false));
1199 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1201 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), true));
1204 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1206 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
1208 case INSN_ALU1_TRAP:
1209 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1211 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
1214 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1216 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
1219 if (unlikely(insn_op_size(insn) <= OP_SIZE_2) || unlikely(insn_op_size(insn) > OP_SIZE_NATIVE))
1221 g(cgen_mul_l(ctx, insn_op_size(insn)));
1223 case INSN_FP_CMP_COND:
1224 g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
1226 case INSN_FP_TEST_REG:
1227 g(cgen_fp_test_reg(ctx, insn_aux(insn)));
1230 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1233 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1235 case INSN_FP_TO_INT32:
1236 case INSN_FP_TO_INT64:
1237 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1239 case INSN_FP_FROM_INT32:
1240 case INSN_FP_FROM_INT64:
1241 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1244 g(cgen_jmp(ctx, insn_jump_size(insn)));
1247 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1249 case INSN_JMP_2REGS:
1251 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
1253 g(cgen_jmp_2regs_mips_r6(ctx, insn_aux(insn), insn_jump_size(insn)));
1255 case INSN_JMP_FP_TEST:
1256 g(cgen_jmp_fp_test(ctx, insn_aux(insn), insn_jump_size(insn)));
1258 case INSN_JMP_INDIRECT:
1259 g(cgen_jmp_call_indirect(ctx, cget_one(ctx), false));
1263 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);