codegen: move gen_imm from arch-specific files to codegen.c
[ajla.git] / c2-mips.inc
blobdf62a2a92a08f49b39a3e436861dbfb12b6d1b53
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  */
19 #define 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)) {
213                         cgen_four(MIPS_NOP);
214                 }
215         }
216         return true;
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);
225         return true;
228 static uint32_t cgen_fp_fmt(unsigned op_size)
230         switch (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);
234                                         return -1U;
235         }
238 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
240         int64_t imm;
241         uint8_t z = R_ZERO;
242         uint8_t *arg1 = ctx->code_position;
243         uint8_t *arg2 = arg1 + arg_size(*arg1);
244         ctx->code_position = arg2 + arg_size(*arg2);
245         if (arg1[0] < 32) {
246                 if (arg2[0] < 32) {
247                         if (sx && size == OP_SIZE_1) {
248                                 cgen_mips_3reg(MIPS_SEB, arg1[0], 0, arg2[0]);
249                                 return true;
250                         }
251                         if (sx && size == OP_SIZE_2) {
252                                 cgen_mips_3reg(MIPS_SEH, arg1[0], 0, arg2[0]);
253                                 return true;
254                         }
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);
258                         return true;
259                 }
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]);
263                         return true;
264                 }
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);
270                         return true;
271                 }
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));
275                         else
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)
278                                 cgen_four(MIPS_NOP);
279                         return true;
280                 }
281                 goto invalid;
282         }
283         if (reg_is_fp(arg1[0])) {
284                 if (arg2[0] < 32) {
285                         uint32_t fmt = cgen_fp_fmt(size);
286                         cgen_mips_fp(MIPS_MTC1, fmt, 0, arg1[0] & 31, arg2[0]);
287                         return true;
288                 }
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);
293                         return true;
294                 }
295                 g(cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_LWC1 : MIPS_LDC1, arg1[0] & 31, arg2));
296                 if (MIPS_LOAD_DELAY_SLOTS)
297                         cgen_four(MIPS_NOP);
298                 return true;
299         }
300         if (arg1[0] == ARG_ADDRESS_1) {
301                 if (arg2[0] == ARG_IMM) {
302                         imm = get_imm(&arg2[1]);
303                         if (unlikely(imm != 0))
304                                 goto invalid;
305                         arg2 = &z;
306                 }
307                 if (arg2[0] < 32) {
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);
309                 }
310                 if (reg_is_fp(arg2[0])) {
311                         return cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_SWC1 : MIPS_SDC1, arg2[0] & 31, arg1);
312                 }
313                 goto invalid;
314         }
316 invalid:
317         internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u, %u", arg1[0], arg2[0], size, (unsigned)sx);
318         return false;
321 static bool attr_w cgen_mov_lr(struct codegen_context *ctx, unsigned size, bool r)
323         int64_t imm;
324         uint32_t mc;
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]))
332                 goto invalid;
334         if (arg1[0] < 32 && arg3[0] == ARG_ADDRESS_1) {
335                 imm = get_imm(&arg3[2]);
336                 if (!r)
337                         mc = size == OP_SIZE_4 ? MIPS_LWL : MIPS_LDL;
338                 else
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)
342                         cgen_four(MIPS_NOP);
343                 return true;
344         } if (arg1[0] == ARG_ADDRESS_1 && arg3[0] < 32) {
345                 imm = get_imm(&arg1[2]);
346                 if (!r)
347                         mc = size == OP_SIZE_4 ? MIPS_SWL : MIPS_SDL;
348                 else
349                         mc = size == OP_SIZE_4 ? MIPS_SWR : MIPS_SDR;
350                 cgen_mips_imm(mc, arg3[0], arg1[1], imm);
351                 return true;
352         }
354 invalid:
355         internal(file_line, "cgen_mov_lr: invalid parameters %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
356         return false;
359 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
361         uint32_t mc;
362         bool swap = false;
363         uint8_t z = R_ZERO;
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);
372                 switch (aux) {
373                         case COND_B:    mc = MIPS_SLTIU; break;
374                         case COND_L:    mc = MIPS_SLTI; break;
375                         default:        goto invalid;
376                 }
377                 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
378                 return true;
379         }
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");
384                 arg2 = &z;
385         }
386         switch (aux) {
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;
392         }
393         if (swap) {
394                 uint8_t *argx = arg2;
395                 arg2 = arg3;
396                 arg3 = argx;
397         }
398         cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
399         return true;
401 invalid:
402         internal(file_line, "cgen_cmp_dest_reg: invalid arguments %u, %02x, %02x, %02x", aux, arg1[0], arg2[0], arg3[0]);
403         return false;
406 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
408         uint32_t mc;
409         int64_t imm = 0;
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;
418                 arg3 = arg2;
419                 arg2 = arg_swp;
420         }
421         if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
422                 uint32_t shift;
423                 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL))
424                         goto invalid;
425                 shift = arg3[1] & ARG_SHIFT_AMOUNT;
426                 if (unlikely(shift < 1) || unlikely(shift > 4))
427                         goto invalid;
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]);
431                 return true;
432         }
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)));
438                 if (alu == ALU_ADD)
439                         mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
440                 else
441                         mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
442                 cgen_mips_3reg(mc, arg1[0], arg2[0], R_AT);
443                 return true;
444         }
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);
450                                 return true;
451                         }
452                         if (imm & 0xFFFFFFFFLL)
453                                 goto invalid;
454                         imm /= 0x100000000LL;
455                         if (imm == (int16_t)imm && size == OP_SIZE_8) {
456                                 if (unlikely(arg1[0] != arg2[0]))
457                                         goto invalid;
458                                 cgen_mips_imm(MIPS_R6_DAHI, 0, arg1[0], imm);
459                                 return true;
460                         }
461                         if (imm & 0xFFFFLL)
462                                 goto invalid;
463                         imm /= 0x10000LL;
464                         if (size == OP_SIZE_8) {
465                                 if (unlikely(arg1[0] != arg2[0]))
466                                         goto invalid;
467                                 cgen_mips_imm(MIPS_R6_DATI, 0, arg1[0], imm);
468                                 return true;
469                         }
470                         goto invalid;
471                 }
472         }
474         if (trap)
475                 g(cgen_trap(ctx, cget_four(ctx)));
477         switch (alu) {
478                 case ALU_MUL:
479                         if (MIPS_R6) {
480                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUL : MIPS_R6_DMUL, arg1[0], arg2[0], arg3[0]);
481                                 return true;
482                         }
483                         if (size == OP_SIZE_4 && MIPS_HAS_MUL) {
484                                 cgen_mips_3reg(MIPS_MUL, arg1[0], arg2[0], arg3[0]);
485                                 return true;
486                         }
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);
489                         return true;
490                 case ALU_UMULH:
491                         if (MIPS_R6) {
492                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUHU : MIPS_R6_DMUHU, arg1[0], arg2[0], arg3[0]);
493                                 return true;
494                         }
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);
497                         return true;
498                 case ALU_SMULH:
499                         if (MIPS_R6) {
500                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUH : MIPS_R6_DMUH, arg1[0], arg2[0], arg3[0]);
501                                 return true;
502                         }
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);
505                         return true;
506                 case ALU_UDIV:
507                         if (MIPS_R6) {
508                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIVU : MIPS_R6_DDIVU, arg1[0], arg2[0], arg3[0]);
509                                 return true;
510                         }
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);
514                         return true;
515                 case ALU_SDIV:
516                         if (MIPS_R6) {
517                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIV : MIPS_R6_DDIV, arg1[0], arg2[0], arg3[0]);
518                                 return true;
519                         }
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);
523                         return true;
524                 case ALU_UREM:
525                         if (MIPS_R6) {
526                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MODU : MIPS_R6_DMODU, arg1[0], arg2[0], arg3[0]);
527                                 return true;
528                         }
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);
532                         return true;
533                 case ALU_SREM:
534                         if (MIPS_R6) {
535                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MOD : MIPS_R6_DMOD, arg1[0], arg2[0], arg3[0]);
536                                 return true;
537                         }
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);
541                         return true;
542         }
544         if (arg3[0] == ARG_IMM) {
545                 imm = get_imm(&arg3[1]);
546                 if (alu == ALU_SUB) {
547                         imm = -(uint64_t)imm;
548                         alu = ALU_ADD;
549                 }
550                 switch (alu) {
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;
553                                         break;
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;
558                 }
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);
562                 return true;
563         }
565         switch (alu) {
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;
568                                 break;
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;
571                                 break;
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;
576         }
577         cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
578         return true;
580 invalid:
581         internal(file_line, "cgen_alu: invalid alu %u, %u, %"PRIxMAX"", size, alu, (uintmax_t)imm);
582         return false;
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);
591         if (trap)
592                 g(cgen_trap(ctx, cget_four(ctx)));
594         switch (alu) {
595                 case ALU1_NOT:  cgen_mips_3reg(MIPS_NOR, arg1[0], R_ZERO, arg2[0]);
596                                 return true;
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]);
599                                 return true;
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]);
602                                 else
603                                         cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DCLZ : MIPS_R6_CLZ, arg1[0], arg2[0], 0);
604                                 return true;
605                 case ALU1_BSWAP:
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);
609                                 } else {
610                                         cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
611                                         cgen_mips_3reg(MIPS_DSHD, arg1[0], 0, arg1[0]);
612                                 }
613                                 return true;
614                 case ALU1_BSWAP16:if (size == OP_SIZE_4) {
615                                         cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
616                                 } else {
617                                         cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
618                                 }
619                                 return true;
620                 case ALU1_BREV: cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DBITSWAP : MIPS_R6_BITSWAP, arg1[0], 0, arg2[0]);
621                                 arg2 = arg1;
622                                 goto bswap;
623                 default:        goto invalid;
624         }
626 invalid:
627         internal(file_line, "cgen_alu1: invalid alu %u, %u", size, alu);
628         return false;
631 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
633         uint32_t mc;
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]);
641                 switch (alu) {
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;
647                 }
648                 cgen_mips_rot_imm(mc, arg1[0], arg2[0], imm);
649                 return true;
650         } else {
651                 switch (alu) {
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;
657                 }
658                 cgen_mips_3reg(mc, arg1[0], arg3[0], arg2[0]);
659                 return true;
660         }
662 invalid:
663         internal(file_line, "cgen_rot: invalid rotation %u, %u", size, alu);
664         return false;
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);
680         return true;
683 static bool fp_condition_negated(unsigned aux)
685         switch (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);
695         }
696         return false;
699 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
701         uint32_t mc, fmt;
702         uint8_t *arg1 = ctx->code_position;
703         uint8_t *arg2 = arg1 + arg_size(*arg1);
704         ctx->code_position = arg2 + arg_size(*arg2);
706         if (MIPS_R6) {
707                 switch (aux) {
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);
717                                                 return false;
718                 }
719         } else {
720                 switch (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);
730                                                 return false;
731                 }
732         }
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)
736                 cgen_four(MIPS_NOP);
737         return true;
740 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx, unsigned aux)
742         unsigned reg = cget_one(ctx);
743         if (MIPS_R6) {
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);
747                 }
748                 if (!fp_condition_negated(aux)) {
749                         cgen_mips_3reg(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, reg, R_ZERO, reg);
750                 } else {
751                         cgen_mips_imm(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, reg, reg, 1);
752                 }
753                 return true;
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);
757         } else {
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);
762         }
763         return true;
766 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
768         uint32_t mc, fmt;
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);
773         switch (aux) {
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);
779         }
780         fmt = cgen_fp_fmt(op_size);
781         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
782         return true;
785 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
787         uint32_t mc, fmt;
788         uint8_t *arg1 = ctx->code_position;
789         uint8_t *arg2 = arg1 + arg_size(*arg1);
790         ctx->code_position = arg2 + arg_size(*arg2);
791         switch (aux) {
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);
795         }
796         fmt = cgen_fp_fmt(op_size);
797         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
798         return true;
801 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
803         uint32_t mc, fmt;
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);
811         }
812         fmt = cgen_fp_fmt(fp_op_size);
813         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
814         return true;
817 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
819         uint32_t mc;
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)
826                         mc = MIPS_CVT_S_W;
827                 else
828                         mc = MIPS_CVT_D_W;
829         } else {
830                 if (fp_op_size == OP_SIZE_4)
831                         mc = MIPS_CVT_S_L;
832                 else
833                         mc = MIPS_CVT_D_L;
834         }
835         cgen_mips_fp(mc, 0, arg1[0] & 31, arg2[0] & 31, 0);
836         return true;
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);
850         if (!MIPS_R6) {
851                 cgen_mips_3reg(MIPS_JR, 0, R_AT, 0);
852                 cgen_four(MIPS_NOP);
853         } else {
854                 cgen_mips_imm(MIPS_R6_JIC, R_AT, 0, 0);
855         }
856         return true;
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);
865                 return true;
866         }
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);
871                 cgen_four(MIPS_NOP);
872                 return true;
873         }
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));
877         return true;
880 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
882         uint32_t mc;
883         uint8_t *arg1 = ctx->code_position;
884         ctx->code_position = arg1 + arg_size(*arg1);
886         if (arg1[0] >= 0x20)
887                 goto invalid;
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));
894                 cgen_four(MIPS_NOP);
895                 return true;
896         }
898         if (length > JMP_SHORTEST)
899                 cond ^= 1;
901         switch (cond) {
902                 case COND_E:    mc = MIPS_BEQ; break;
903                 case COND_NE:   mc = MIPS_BNE; break;
904                 case COND_S:
905                 case COND_L:    mc = MIPS_BLTZ; break;
906                 case COND_LE:   mc = MIPS_BLEZ; break;
907                 case COND_G:    mc = MIPS_BGTZ; break;
908                 case COND_NS:
909                 case COND_GE:   mc = MIPS_BGEZ; break;
910                 default:        goto invalid;
911         }
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);
917                 cgen_four(MIPS_NOP);
918                 return true;
919         }
920         if (MIPS_R6 && length <= JMP_LONG) {
921                 g(cgen_jump_not_last(ctx, 3));
922                 cgen_mips_imm(mc, 0, arg1[0], 2);
923                 cgen_four(MIPS_NOP);
924                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
925                 cgen_four(MIPS_R6_BC);
926                 return true;
927         }
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));
932         return true;
934 invalid:
935         internal(file_line, "cgen_jmp_reg: invalid arguments %u, %u, %02x", cond, length, arg1[0]);
936         return false;
939 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
941         uint32_t mc;
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))
946                 goto invalid;
948         if (length > JMP_SHORTEST)
949                 cond ^= 1;
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);
957                 cgen_four(MIPS_NOP);
958                 return true;
959         }
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));
964         return true;
966 invalid:
967         internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
968         return false;
971 static bool attr_w cgen_jmp_2regs_mips_r6(struct codegen_context *ctx, unsigned cond, unsigned length)
973         uint32_t mc;
974         bool swap = false;
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)
980                 goto invalid;
982         if (arg1[0] == arg2[0]) {
983                 cgen_mips_3reg(MIPS_OR, R_AT, arg2[0], R_ZERO);
984                 arg2 = arg3;
985         }
987         if (length > JMP_SHORTEST)
988                 cond ^= 1;
990         switch (cond) {
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;
997                 case COND_S:
998                 case COND_L:    mc = MIPS_R6_BLTC; break;
999                 case COND_NS:
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;
1004         }
1005         if (!swap) {
1006                 uint8_t *argx = arg1;
1007                 arg1 = arg2;
1008                 arg2 = argx;
1009         }
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);
1015                 return true;
1016         }
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);
1022                 return true;
1023         }
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));
1027         return true;
1029 invalid:
1030         internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
1031         return false;
1034 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned aux, unsigned length)
1036         uint32_t mc;
1037         bool t = true;
1038         if (fp_condition_negated(aux))
1039                 t = !t;
1040         if (length > JMP_SHORTEST)
1041                 t = !t;
1042         if (MIPS_R6) {
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);
1049                         return true;
1050                 }
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);
1057                         return true;
1058                 }
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));
1063                 return true;
1064         } else {
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);
1071                         return true;
1072                 }
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));
1077                 return true;
1078         }
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));
1084         if (!call) {
1085                 if (!MIPS_R6) {
1086                         cgen_mips_3reg(MIPS_JR, 0, reg, 0);
1087                         cgen_four(MIPS_NOP);
1088                 } else {
1089                         cgen_mips_imm(MIPS_R6_JIC, reg, 0, 0);
1090                 }
1091         } else {
1092                 if (!MIPS_R6) {
1093                         cgen_mips_3reg(MIPS_JALR, R_RA, reg, 0);
1094                         cgen_four(MIPS_NOP);
1095                 } else {
1096                         cgen_mips_imm(MIPS_R6_JIALC, reg, 0, 0);
1097                 }
1098         }
1099         return true;
1103 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1105         uint32_t mc;
1106         int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1107         switch (reloc->length) {
1108                 case JMP_SHORTEST:
1109                         offs /= 4;
1110                         offs--;
1111                         if (offs != (int16_t)offs)
1112                                 return false;
1113                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1114                         mc &= ~0xFFFFU;
1115                         mc |= offs & 0xFFFFU;
1116                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1117                         return true;
1118                 case JMP_SHORT:
1119                         offs /= 4;
1120                         offs--;
1121                         if (offs < -0x00100000 || offs >= 0x00100000)
1122                                 return false;
1123                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1124                         mc &= ~0x001FFFFFU;
1125                         mc |= offs & 0x001FFFFFU;
1126                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1127                         return true;
1128                 case JMP_LONG:
1129                         offs /= 4;
1130                         offs--;
1131                         if (offs < -0x02000000 || offs >= 0x02000000)
1132                                 return false;
1133                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1134                         mc &= ~0x03FFFFFFU;
1135                         mc |= offs & 0x03FFFFFFU;
1136                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1137                         return true;
1138                 case JMP_EXTRA_LONG:
1139                         offs -= 12;
1140                         if (offs != (int32_t)offs)
1141                                 return false;
1142                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1143                         mc &= ~0xFFFFU;
1144                         mc |= ((uint64_t)offs >> 16) & 0xFFFFU;
1145                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1146                         memcpy(&mc, ctx->mcode + reloc->position + 8, 4);
1147                         mc &= ~0xFFFFU;
1148                         mc |= offs & 0xFFFFU;
1149                         memcpy(ctx->mcode + reloc->position + 8, &mc, 4);
1150                         return true;
1151                 default:
1152                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1153         }
1154         return false;
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))
1162                         goto invalid_insn;
1163         }
1164         switch (insn_opcode(insn)) {
1165                 case INSN_ENTRY:
1166                         g(cgen_entry(ctx));
1167                         return true;
1168                 case INSN_LABEL:
1169                         g(cgen_label(ctx));
1170                         return true;
1171                 case INSN_RET:
1172                         g(cgen_jmp_call_indirect(ctx, R_RA, false));
1173                         if (MIPS_R6)
1174                                 cgen_four(MIPS_NOP);
1175                         return true;
1176                 case INSN_CALL_INDIRECT:
1177                         g(cgen_jmp_call_indirect(ctx, cget_one(ctx), true));
1178                         return true;
1179                 case INSN_MOV:
1180                         g(cgen_mov(ctx, insn_op_size(insn), false));
1181                         return true;
1182                 case INSN_MOVSX:
1183                         g(cgen_mov(ctx, insn_op_size(insn), true));
1184                         return true;
1185                 case INSN_MOV_LR:
1186                         g(cgen_mov_lr(ctx, insn_op_size(insn), insn_aux(insn) != 0));
1187                         return true;
1188                 case INSN_CMP_DEST_REG:
1189                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1190                                 goto invalid_insn;
1191                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
1192                         return true;
1193                 case INSN_ALU:
1194                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1195                                 goto invalid_insn;
1196                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), false));
1197                         return true;
1198                 case INSN_ALU_TRAP:
1199                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1200                                 goto invalid_insn;
1201                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), true));
1202                         return true;
1203                 case INSN_ALU1:
1204                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1205                                 goto invalid_insn;
1206                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
1207                         return true;
1208                 case INSN_ALU1_TRAP:
1209                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1210                                 goto invalid_insn;
1211                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
1212                         return true;
1213                 case INSN_ROT:
1214                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1215                                 goto invalid_insn;
1216                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
1217                         return true;
1218                 case INSN_MUL_L:
1219                         if (unlikely(insn_op_size(insn) <= OP_SIZE_2) || unlikely(insn_op_size(insn) > OP_SIZE_NATIVE))
1220                                 goto invalid_insn;
1221                         g(cgen_mul_l(ctx, insn_op_size(insn)));
1222                         return true;
1223                 case INSN_FP_CMP_COND:
1224                         g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
1225                         return true;
1226                 case INSN_FP_TEST_REG:
1227                         g(cgen_fp_test_reg(ctx, insn_aux(insn)));
1228                         return true;
1229                 case INSN_FP_ALU:
1230                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1231                         return true;
1232                 case INSN_FP_ALU1:
1233                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1234                         return true;
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)));
1238                         return true;
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)));
1242                         return true;
1243                 case INSN_JMP:
1244                         g(cgen_jmp(ctx, insn_jump_size(insn)));
1245                         return true;
1246                 case INSN_JMP_REG:
1247                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1248                         return true;
1249                 case INSN_JMP_2REGS:
1250                         if (!MIPS_R6)
1251                                 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
1252                         else
1253                                 g(cgen_jmp_2regs_mips_r6(ctx, insn_aux(insn), insn_jump_size(insn)));
1254                         return true;
1255                 case INSN_JMP_FP_TEST:
1256                         g(cgen_jmp_fp_test(ctx, insn_aux(insn), insn_jump_size(insn)));
1257                         return true;
1258                 case INSN_JMP_INDIRECT:
1259                         g(cgen_jmp_call_indirect(ctx, cget_one(ctx), false));
1260                         return true;
1261                 default:
1262                 invalid_insn:
1263                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
1264                         return false;
1265         }