powerpc: improve the code for inc, dec and neg
[ajla.git] / c2-mips.inc
blobea925abe1b9e9a5a07776a81cc4a70dbf61ee2e5
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_BC1F               0x45000000U
88 #define MIPS_BC1T               0x45010000U
89 #define MIPS_ADD_FP             0x46000000U
90 #define MIPS_SUB_FP             0x46000001U
91 #define MIPS_MUL_FP             0x46000002U
92 #define MIPS_DIV_FP             0x46000003U
93 #define MIPS_SQRT_FP            0x46000004U
94 #define MIPS_NEG_FP             0x46000007U
95 #define MIPS_TRUNC_L            0x46000009U
96 #define MIPS_TRUNC_W            0x4600000dU
97 #define MIPS_C_F                0x46000030U
98 #define MIPS_C_UN               0x46000031U
99 #define MIPS_C_EQ               0x46000032U
100 #define MIPS_C_UEQ              0x46000033U
101 #define MIPS_C_OLT              0x46000034U
102 #define MIPS_C_ULT              0x46000035U
103 #define MIPS_C_OLE              0x46000036U
104 #define MIPS_C_ULE              0x46000037U
105 #define MIPS_FP_SINGLE                  0x00U
106 #define MIPS_FP_DOUBLE                  0x01U
107 #define MIPS_CVT_S_W            0x46800020U
108 #define MIPS_CVT_D_W            0x46800021U
109 #define MIPS_CVT_S_L            0x46a00020U
110 #define MIPS_CVT_D_L            0x46a00021U
111 #define MIPS_DADDI              0x60000000U
112 #define MIPS_DADDIU             0x64000000U
113 #define MIPS_LDL                0x68000000U
114 #define MIPS_LDR                0x6c000000U
115 #define MIPS_MUL                0x70000002U
116 #define MIPS_CLZ                0x70000020U
117 #define MIPS_DCLZ               0x70000024U
118 #define MIPS_WSBH               0x7c0000a0U
119 #define MIPS_DSBH               0x7c0000a4U
120 #define MIPS_DSHD               0x7c000164U
121 #define MIPS_SEB                0x7c000420U
122 #define MIPS_SEH                0x7c000620U
123 #define MIPS_LB                 0x80000000U
124 #define MIPS_LH                 0x84000000U
125 #define MIPS_LWL                0x88000000U
126 #define MIPS_LW                 0x8c000000U
127 #define MIPS_LBU                0x90000000U
128 #define MIPS_LHU                0x94000000U
129 #define MIPS_LWR                0x98000000U
130 #define MIPS_LWU                0x9c000000U
131 #define MIPS_SB                 0xa0000000U
132 #define MIPS_SH                 0xa4000000U
133 #define MIPS_SWL                0xa8000000U
134 #define MIPS_SW                 0xac000000U
135 #define MIPS_SDL                0xb0000000U
136 #define MIPS_SDR                0xb4000000U
137 #define MIPS_SWR                0xb8000000U
138 #define MIPS_LWC1               0xc4000000U
139 #define MIPS_LDC1               0xd4000000U
140 #define MIPS_LD                 0xdc000000U
141 #define MIPS_SWC1               0xe4000000U
142 #define MIPS_SDC1               0xf4000000U
143 #define MIPS_SD                 0xfc000000U
145 #define MIPS_R6_LSA             0x00000005U
146 #define MIPS_R6_JALR            0x00000009U
147 #define MIPS_R6_DLSA            0x00000015U
148 #define MIPS_R6_CLZ             0x00000050U
149 #define MIPS_R6_DCLZ            0x00000052U
150 #define MIPS_R6_MUL             0x00000098U
151 #define MIPS_R6_MULU            0x00000099U
152 #define MIPS_R6_DIV             0x0000009aU
153 #define MIPS_R6_DIVU            0x0000009bU
154 #define MIPS_R6_DMUL            0x0000009cU
155 #define MIPS_R6_DMULU           0x0000009dU
156 #define MIPS_R6_DDIV            0x0000009eU
157 #define MIPS_R6_DDIVU           0x0000009fU
158 #define MIPS_R6_MUH             0x000000d8U
159 #define MIPS_R6_MUHU            0x000000d9U
160 #define MIPS_R6_MOD             0x000000daU
161 #define MIPS_R6_MODU            0x000000dbU
162 #define MIPS_R6_DMUH            0x000000dcU
163 #define MIPS_R6_DMUHU           0x000000ddU
164 #define MIPS_R6_DMOD            0x000000deU
165 #define MIPS_R6_DMODU           0x000000dfU
166 #define MIPS_R6_DAHI            0x04060000U
167 #define MIPS_R6_DATI            0x041e0000U
168 #define MIPS_R6_AUI             0x3c000000U
169 #define MIPS_R6_BC1EQZ          0x45200000U
170 #define MIPS_R6_BC1NEZ          0x45a00000U
171 #define MIPS_R6_CMP_AF          0x46800000U
172 #define MIPS_R6_CMP_UN          0x46800001U
173 #define MIPS_R6_CMP_EQ          0x46800002U
174 #define MIPS_R6_CMP_UEQ         0x46800003U
175 #define MIPS_R6_CMP_LT          0x46800004U
176 #define MIPS_R6_CMP_ULT         0x46800005U
177 #define MIPS_R6_CMP_LE          0x46800006U
178 #define MIPS_R6_CMP_ULE         0x46800007U
179 #define MIPS_R6_CMP_OR          0x46800011U
180 #define MIPS_R6_CMP_UNE         0x46800012U
181 #define MIPS_R6_CMP_NE          0x46800013U
182 #define MIPS_R6_BGEZC           0x58000000U
183 #define MIPS_R6_BLEZC           0x58000000U
184 #define MIPS_R6_BGTZC           0x5c000000U
185 #define MIPS_R6_BLTZC           0x5c000000U
186 #define MIPS_R6_DAUI            0x74000000U
187 #define MIPS_R6_BITSWAP         0x7c000020U
188 #define MIPS_R6_DBITSWAP        0x7c000024U
189 #define MIPS_R6_BC              0xc8000000U
190 #define MIPS_R6_JIC             0xd8000000U
191 #define MIPS_R6_BEQZC           0xd8000000U
192 #define MIPS_R6_JIALC           0xf8000000U
193 #define MIPS_R6_BNEZC           0xf8000000U
195 #define cgen_mips_3reg(mc, rd, rs, rt) \
196         cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rs) << 21) | ((uint32_t)(rt) << 16))
197 #define cgen_mips_rot_imm(mc, rd, rt, sa) \
198         cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rt) << 16) | (((sa) & 0x1f) << 6))
199 #define cgen_mips_imm(mc, rt, rs, imm) \
200         cgen_four((mc) | ((uint32_t)(rt) << 16) | ((uint32_t)(rs) << 21) | ((imm) & 0xffff))
201 #define cgen_mips_fp(mc, fmt, fd, fs, ft) \
202         cgen_four((mc) | ((uint32_t)(fmt) << 21) | ((uint32_t)(fd) << 6) | ((uint32_t)(fs) << 11) | ((uint32_t)(ft) << 16))
204 static bool attr_w cgen_jump_not_last(struct codegen_context *ctx, unsigned insns)
206         if (MIPS_R4000_ERRATA) {
207                 while (unlikely((ctx->mcode_size & 0xfffU) + insns * 4 >= 0x1000U)) {
208                         cgen_four(MIPS_NOP);
209                 }
210         }
211         return true;
214 static bool attr_w cgen_ls(struct codegen_context *ctx, uint32_t mc, uint8_t arg1, uint8_t *arg2)
216         int64_t imm = get_imm(&arg2[2]);
217         if (unlikely(imm != (int16_t)imm))
218                 internal(file_line, "cgen_ls: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
219         cgen_mips_imm(mc, arg1, arg2[1], imm);
220         return true;
223 static uint32_t cgen_fp_fmt(unsigned op_size)
225         switch (op_size) {
226                 case OP_SIZE_4:         return MIPS_FP_SINGLE;
227                 case OP_SIZE_8:         return MIPS_FP_DOUBLE;
228                 default:                internal(file_line, "cgen_fp_fmt: invalid size %u", op_size);
229                                         return -1U;
230         }
233 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
235         int64_t imm;
236         uint8_t z = R_ZERO;
237         uint8_t *arg1 = ctx->code_position;
238         uint8_t *arg2 = arg1 + arg_size(*arg1);
239         ctx->code_position = arg2 + arg_size(*arg2);
240         if (arg1[0] < 32) {
241                 if (arg2[0] < 32) {
242                         if (sx && size == OP_SIZE_1) {
243                                 cgen_mips_3reg(MIPS_SEB, arg1[0], 0, arg2[0]);
244                                 return true;
245                         }
246                         if (sx && size == OP_SIZE_2) {
247                                 cgen_mips_3reg(MIPS_SEH, arg1[0], 0, arg2[0]);
248                                 return true;
249                         }
250                         if (unlikely(size != OP_SIZE_NATIVE))
251                                 internal(file_line, "cgen_mov: unsupported size %u", size);
252                         cgen_mips_3reg(MIPS_OR, arg1[0], arg2[0], R_ZERO);
253                         return true;
254                 }
255                 if (arg2[0] < 64) {
256                         uint32_t fmt = cgen_fp_fmt(size);
257                         cgen_mips_fp(MIPS_MFC1, fmt, 0, arg2[0] & 31, arg1[0]);
258                         return true;
259                 }
260                 if (arg2[0] == ARG_IMM) {
261                         imm = get_imm(&arg2[1]);
262                         if (unlikely((imm & 0xffff) != 0) || unlikely(imm != (int32_t)imm))
263                                 internal(file_line, "cgen_mov: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
264                         cgen_mips_imm(MIPS_LUI, arg1[0], 0, (uint64_t)imm >> 16);
265                         return true;
266                 }
267                 if (arg2[0] == ARG_ADDRESS_1) {
268                         if (!sx && size != OP_SIZE_NATIVE)
269                                 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LBU : size == OP_SIZE_2 ? MIPS_LHU : MIPS_LWU, arg1[0], arg2));
270                         else
271                                 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LB : size == OP_SIZE_2 ? MIPS_LH : size == OP_SIZE_4 ? MIPS_LW : MIPS_LD, arg1[0], arg2));
272                         if (MIPS_LOAD_DELAY_SLOTS)
273                                 cgen_four(MIPS_NOP);
274                         return true;
275                 }
276                 goto invalid;
277         }
278         if (arg1[0] < 64) {
279                 if (arg2[0] < 64)
280                         goto invalid;
281                 g(cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_LWC1 : MIPS_LDC1, arg1[0] & 31, arg2));
282                 if (MIPS_LOAD_DELAY_SLOTS)
283                         cgen_four(MIPS_NOP);
284                 return true;
285         }
286         if (arg1[0] == ARG_ADDRESS_1) {
287                 if (arg2[0] == ARG_IMM) {
288                         imm = get_imm(&arg2[1]);
289                         if (unlikely(imm != 0))
290                                 goto invalid;
291                         arg2 = &z;
292                 }
293                 if (arg2[0] < 32) {
294                         return cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_SB : size == OP_SIZE_2 ? MIPS_SH : size == OP_SIZE_4 ? MIPS_SW : MIPS_SD, arg2[0], arg1);
295                 }
296                 if (arg2[0] < 64) {
297                         return cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_SWC1 : MIPS_SDC1, arg2[0] & 31, arg1);
298                 }
299                 goto invalid;
300         }
302 invalid:
303         internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u, %u", arg1[0], arg2[0], size, (unsigned)sx);
304         return false;
307 static bool attr_w cgen_mov_lr(struct codegen_context *ctx, unsigned size, bool r)
309         int64_t imm;
310         uint32_t mc;
311         uint8_t *arg1, *arg2, *arg3;
312         arg1 = ctx->code_position;
313         arg2 = arg1 + arg_size(*arg1);
314         arg3 = arg2 + arg_size(*arg2);
315         ctx->code_position = arg3 + arg_size(*arg3);
317         if (unlikely(arg1[0] != arg2[0]))
318                 goto invalid;
320         if (arg1[0] < 32 && arg3[0] == ARG_ADDRESS_1) {
321                 imm = get_imm(&arg3[2]);
322                 if (!r)
323                         mc = size == OP_SIZE_4 ? MIPS_LWL : MIPS_LDL;
324                 else
325                         mc = size == OP_SIZE_4 ? MIPS_LWR : MIPS_LDR;
326                 cgen_mips_imm(mc, arg1[0], arg3[1], imm);
327                 if (MIPS_LOAD_DELAY_SLOTS)
328                         cgen_four(MIPS_NOP);
329                 return true;
330         } if (arg1[0] == ARG_ADDRESS_1 && arg3[0] < 32) {
331                 imm = get_imm(&arg1[2]);
332                 if (!r)
333                         mc = size == OP_SIZE_4 ? MIPS_SWL : MIPS_SDL;
334                 else
335                         mc = size == OP_SIZE_4 ? MIPS_SWR : MIPS_SDR;
336                 cgen_mips_imm(mc, arg3[0], arg1[1], imm);
337                 return true;
338         }
340 invalid:
341         internal(file_line, "cgen_mov_lr: invalid parameters %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
342         return false;
345 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
347         uint32_t mc;
348         bool swap = false;
349         uint8_t z = R_ZERO;
350         uint8_t *arg1 = ctx->code_position;
351         uint8_t *arg2 = arg1 + arg_size(*arg1);
352         uint8_t *arg3 = arg2 + arg_size(*arg2);
353         ctx->code_position = arg3 + arg_size(*arg3);
354         if (arg3[0] == ARG_IMM) {
355                 int64_t imm = get_imm(&arg3[1]);
356                 if (unlikely(imm != (int16_t)imm))
357                         internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
358                 switch (aux) {
359                         case COND_B:    mc = MIPS_SLTIU; break;
360                         case COND_L:    mc = MIPS_SLTI; break;
361                         default:        goto invalid;
362                 }
363                 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
364                 return true;
365         }
366         if (arg2[0] == ARG_IMM) {
367                 int64_t imm = get_imm(&arg2[1]);
368                 if (unlikely(imm != 0))
369                         internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
370                 arg2 = &z;
371         }
372         switch (aux) {
373                 case COND_B:    mc = MIPS_SLTU; break;
374                 case COND_A:    mc = MIPS_SLTU; swap = true; break;
375                 case COND_L:    mc = MIPS_SLT; break;
376                 case COND_G:    mc = MIPS_SLT; swap = true; break;
377                 default:        goto invalid;
378         }
379         if (swap) {
380                 uint8_t *argx = arg2;
381                 arg2 = arg3;
382                 arg3 = argx;
383         }
384         cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
385         return true;
387 invalid:
388         internal(file_line, "cgen_cmp_dest_reg: invalid arguments %u, %02x, %02x, %02x", aux, arg1[0], arg2[0], arg3[0]);
389         return false;
392 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
394         uint32_t mc;
395         int64_t imm = 0;
396         bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
397         uint8_t *arg1 = ctx->code_position;
398         uint8_t *arg2 = arg1 + arg_size(*arg1);
399         uint8_t *arg3 = arg2 + arg_size(*arg2);
400         ctx->code_position = arg3 + arg_size(*arg3);
402         if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
403                 uint8_t *arg_swp = arg3;
404                 arg3 = arg2;
405                 arg2 = arg_swp;
406         }
407         if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
408                 uint32_t shift;
409                 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL))
410                         goto invalid;
411                 shift = arg3[1] & ARG_SHIFT_AMOUNT;
412                 if (unlikely(shift < 1) || unlikely(shift > 4))
413                         goto invalid;
414                 mc = size == OP_SIZE_8 ? MIPS_R6_DLSA : MIPS_R6_LSA;
415                 mc |= (shift - 1) << 6;
416                 cgen_mips_3reg(mc, arg1[0], arg3[2], arg2[0]);
417                 return true;
418         }
420         if ((alu == ALU_ADD || alu == ALU_SUB) && arg3[0] == ARG_IMM && trap && !have_imm_trap) {
421                 imm = get_imm(&arg3[1]);
422                 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, imm);
423                 g(cgen_trap(ctx, cget_four(ctx)));
424                 if (alu == ALU_ADD)
425                         mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
426                 else
427                         mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
428                 cgen_mips_3reg(mc, arg1[0], arg2[0], R_AT);
429                 return true;
430         }
431         if (MIPS_R6 && alu == ALU_ADD && arg3[0] == ARG_IMM && !trap) {
432                 imm = get_imm(&arg3[1]);
433                 if (imm && !(imm & 0xffff)) {
434                         if (imm == (int32_t)imm) {
435                                 cgen_mips_imm(size == OP_SIZE_4 ? MIPS_R6_AUI : MIPS_R6_DAUI, arg1[0], arg2[0], (uint64_t)imm >> 16);
436                                 return true;
437                         }
438                         if (imm & 0xFFFFFFFFLL)
439                                 goto invalid;
440                         imm /= 0x100000000LL;
441                         if (imm == (int16_t)imm && size == OP_SIZE_8) {
442                                 if (unlikely(arg1[0] != arg2[0]))
443                                         goto invalid;
444                                 cgen_mips_imm(MIPS_R6_DAHI, 0, arg1[0], imm);
445                                 return true;
446                         }
447                         if (imm & 0xFFFFLL)
448                                 goto invalid;
449                         imm /= 0x10000LL;
450                         if (size == OP_SIZE_8) {
451                                 if (unlikely(arg1[0] != arg2[0]))
452                                         goto invalid;
453                                 cgen_mips_imm(MIPS_R6_DATI, 0, arg1[0], imm);
454                                 return true;
455                         }
456                         goto invalid;
457                 }
458         }
460         if (trap)
461                 g(cgen_trap(ctx, cget_four(ctx)));
463         switch (alu) {
464                 case ALU_MUL:
465                         if (MIPS_R6) {
466                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUL : MIPS_R6_DMUL, arg1[0], arg2[0], arg3[0]);
467                                 return true;
468                         }
469                         if (size == OP_SIZE_4 && MIPS_HAS_MUL) {
470                                 cgen_mips_3reg(MIPS_MUL, arg1[0], arg2[0], arg3[0]);
471                                 return true;
472                         }
473                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
474                         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
475                         return true;
476                 case ALU_UMULH:
477                         if (MIPS_R6) {
478                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUHU : MIPS_R6_DMUHU, arg1[0], arg2[0], arg3[0]);
479                                 return true;
480                         }
481                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
482                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
483                         return true;
484                 case ALU_SMULH:
485                         if (MIPS_R6) {
486                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUH : MIPS_R6_DMUH, arg1[0], arg2[0], arg3[0]);
487                                 return true;
488                         }
489                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg2[0], arg3[0]);
490                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
491                         return true;
492                 case ALU_UDIV:
493                         if (MIPS_R6) {
494                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIVU : MIPS_R6_DDIVU, arg1[0], arg2[0], arg3[0]);
495                                 return true;
496                         }
497                         g(cgen_jump_not_last(ctx, 1));
498                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
499                         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
500                         return true;
501                 case ALU_SDIV:
502                         if (MIPS_R6) {
503                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIV : MIPS_R6_DDIV, arg1[0], arg2[0], arg3[0]);
504                                 return true;
505                         }
506                         g(cgen_jump_not_last(ctx, 1));
507                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
508                         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
509                         return true;
510                 case ALU_UREM:
511                         if (MIPS_R6) {
512                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MODU : MIPS_R6_DMODU, arg1[0], arg2[0], arg3[0]);
513                                 return true;
514                         }
515                         g(cgen_jump_not_last(ctx, 1));
516                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
517                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
518                         return true;
519                 case ALU_SREM:
520                         if (MIPS_R6) {
521                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MOD : MIPS_R6_DMOD, arg1[0], arg2[0], arg3[0]);
522                                 return true;
523                         }
524                         g(cgen_jump_not_last(ctx, 1));
525                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
526                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
527                         return true;
528         }
530         if (arg3[0] == ARG_IMM) {
531                 imm = get_imm(&arg3[1]);
532                 if (alu == ALU_SUB) {
533                         imm = -(uint64_t)imm;
534                         alu = ALU_ADD;
535                 }
536                 switch (alu) {
537                         case ALU_ADD:   if (trap) mc = size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI;
538                                         else mc = size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU;
539                                         break;
540                         case ALU_XOR:   mc = MIPS_XORI; break;
541                         case ALU_OR:    mc = MIPS_ORI; break;
542                         case ALU_AND:   mc = MIPS_ANDI; break;
543                         default:        goto invalid;
544                 }
545                 if (unlikely(imm != (alu == ALU_ADD ? (int64_t)(int16_t)imm : (int64_t)(uint16_t)imm)))
546                         internal(file_line, "cgen_alu: invalid imm: %"PRIxMAX" (%u)", (uintmax_t)imm, alu);
547                 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
548                 return true;
549         }
551         switch (alu) {
552                 case ALU_ADD:   if (trap) mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
553                                 else mc = size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU;
554                                 break;
555                 case ALU_SUB:   if (trap) mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
556                                 else mc = size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU;
557                                 break;
558                 case ALU_XOR:   mc = MIPS_XOR; break;
559                 case ALU_OR:    mc = MIPS_OR; break;
560                 case ALU_AND:   mc = MIPS_AND; break;
561                 default:        goto invalid;
562         }
563         cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
564         return true;
566 invalid:
567         internal(file_line, "cgen_alu: invalid alu %u, %u, %"PRIxMAX"", size, alu, (uintmax_t)imm);
568         return false;
571 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
573         bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
574         int cnst = alu == ALU1_INC ? 1 : alu == ALU1_DEC ? -1 : 0;
575         uint8_t *arg1 = ctx->code_position;
576         uint8_t *arg2 = arg1 + arg_size(*arg1);
577         ctx->code_position = arg2 + arg_size(*arg2);
579         if (cnst && trap && !have_imm_trap) {
580                 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
581                 g(cgen_trap(ctx, cget_four(ctx)));
582                 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD, arg1[0], arg2[0], R_AT);
583                 return true;
584         }
585         if (MIPS_R4000_ERRATA && cnst && !trap && size == OP_SIZE_8) {  /* R4000 has broken DADDIU */
586                 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
587                 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, arg1[0], arg2[0], R_AT);
588                 return true;
589         }
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_INC:
601                 case ALU1_DEC:  if (trap) cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI, arg1[0], arg2[0], cnst);
602                                 else cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, arg1[0], arg2[0], cnst);
603                                 return true;
604                 case ALU1_LZCNT: if (!MIPS_R6)
605                                         cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DCLZ : MIPS_CLZ, arg1[0], arg2[0], arg1[0]);
606                                 else
607                                         cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DCLZ : MIPS_R6_CLZ, arg1[0], arg2[0], 0);
608                                 return true;
609                 case ALU1_BSWAP:
610                 bswap:          if (size == OP_SIZE_4) {
611                                         cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
612                                         cgen_mips_rot_imm(MIPS_ROTR, arg1[0], arg1[0], 16);
613                                 } else {
614                                         cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
615                                         cgen_mips_3reg(MIPS_DSHD, arg1[0], 0, arg1[0]);
616                                 }
617                                 return true;
618                 case ALU1_BSWAP16:if (size == OP_SIZE_4) {
619                                         cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
620                                 } else {
621                                         cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
622                                 }
623                                 return true;
624                 case ALU1_BREV: cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DBITSWAP : MIPS_R6_BITSWAP, arg1[0], 0, arg2[0]);
625                                 arg2 = arg1;
626                                 goto bswap;
627                 default:        goto invalid;
628         }
630 invalid:
631         internal(file_line, "cgen_alu1: invalid alu %u, %u", size, alu);
632         return false;
635 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
637         uint32_t mc;
638         uint8_t *arg1 = ctx->code_position;
639         uint8_t *arg2 = arg1 + arg_size(*arg1);
640         uint8_t *arg3 = arg2 + arg_size(*arg2);
641         ctx->code_position = arg3 + arg_size(*arg3);
643         if (arg3[0] == ARG_IMM) {
644                 int64_t imm = get_imm(&arg3[1]);
645                 switch (alu) {
646                         case ROT_SHL:   mc = size == OP_SIZE_4 ? MIPS_SLL : imm & 0x20 ? MIPS_DSLL32 : MIPS_DSLL; break;
647                         case ROT_SHR:   mc = size == OP_SIZE_4 ? MIPS_SRL : imm & 0x20 ? MIPS_DSRL32 : MIPS_DSRL; break;
648                         case ROT_SAR:   mc = size == OP_SIZE_4 ? MIPS_SRA : imm & 0x20 ? MIPS_DSRA32 : MIPS_DSRA; break;
649                         case ROT_ROR:   mc = size == OP_SIZE_4 ? MIPS_ROTR : imm & 0x20 ? MIPS_DROTR32 : MIPS_DROTR; break;
650                         default:        goto invalid;
651                 }
652                 cgen_mips_rot_imm(mc, arg1[0], arg2[0], imm);
653                 return true;
654         } else {
655                 switch (alu) {
656                         case ROT_SHL:   mc = size == OP_SIZE_4 ? MIPS_SLLV : MIPS_DSLLV; break;
657                         case ROT_SHR:   mc = size == OP_SIZE_4 ? MIPS_SRLV : MIPS_DSRLV; break;
658                         case ROT_SAR:   mc = size == OP_SIZE_4 ? MIPS_SRAV : MIPS_DSRAV; break;
659                         case ROT_ROR:   mc = size == OP_SIZE_4 ? MIPS_ROTRV : MIPS_DROTRV; break;
660                         default:        goto invalid;
661                 }
662                 cgen_mips_3reg(mc, arg1[0], arg3[0], arg2[0]);
663                 return true;
664         }
666 invalid:
667         internal(file_line, "cgen_rot: invalid rotation %u, %u", size, alu);
668         return false;
671 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size)
673         uint8_t *arg1, *arg2, *arg3, *arg4;
674         arg1 = ctx->code_position;
675         arg2 = arg1 + arg_size(*arg1);
676         arg3 = arg2 + arg_size(*arg2);
677         arg4 = arg3 + arg_size(*arg3);
678         ctx->code_position = arg4 + arg_size(*arg4);
680         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg3[0], arg4[0]);
681         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
682         cgen_mips_3reg(MIPS_MFHI, arg2[0], 0, 0);
684         return true;
687 static bool fp_condition_negated(unsigned aux)
689         switch (aux) {
690                 case FP_COND_P:         return false;
691                 case FP_COND_E:         return false;
692                 case FP_COND_B:         return false;
693                 case FP_COND_BE:        return false;
694                 case FP_COND_NP:        return true;
695                 case FP_COND_NE:        return true;
696                 case FP_COND_AE:        return true;
697                 case FP_COND_A:         return true;
698                 default:                internal(file_line, "fp_condition_negated: invalid condition %u", aux);
699         }
700         return false;
703 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
705         uint32_t mc, fmt;
706         uint8_t *arg1 = ctx->code_position;
707         uint8_t *arg2 = arg1 + arg_size(*arg1);
708         ctx->code_position = arg2 + arg_size(*arg2);
710         if (MIPS_R6) {
711                 switch (aux) {
712                         case FP_COND_P:         mc = MIPS_R6_CMP_UN; break;
713                         case FP_COND_E:         mc = MIPS_R6_CMP_EQ; break;
714                         case FP_COND_B:         mc = MIPS_R6_CMP_LT; break;
715                         case FP_COND_BE:        mc = MIPS_R6_CMP_LE; break;
716                         case FP_COND_NP:        mc = MIPS_R6_CMP_UN; break;
717                         case FP_COND_NE:        mc = MIPS_R6_CMP_EQ; break;
718                         case FP_COND_AE:        mc = MIPS_R6_CMP_LT; break;
719                         case FP_COND_A:         mc = MIPS_R6_CMP_LE; break;
720                         default:                internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
721                                                 return false;
722                 }
723         } else {
724                 switch (aux) {
725                         case FP_COND_P:         mc = MIPS_C_UN; break;
726                         case FP_COND_E:         mc = MIPS_C_EQ; break;
727                         case FP_COND_B:         mc = MIPS_C_OLT; break;
728                         case FP_COND_BE:        mc = MIPS_C_OLE; break;
729                         case FP_COND_NP:        mc = MIPS_C_UN; break;
730                         case FP_COND_NE:        mc = MIPS_C_EQ; break;
731                         case FP_COND_AE:        mc = MIPS_C_OLT; break;
732                         case FP_COND_A:         mc = MIPS_C_OLE; break;
733                         default:                internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
734                                                 return false;
735                 }
736         }
737         fmt = cgen_fp_fmt(op_size);
738         cgen_mips_fp(mc, fmt, MIPS_R6 ? FR_CMP_RESULT & 31 : 0, arg1[0] & 31, arg2[0] & 31);
739         if (MIPS_FCMP_DELAY_SLOTS)
740                 cgen_four(MIPS_NOP);
741         return true;
744 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx, unsigned aux)
746         unsigned reg = cget_one(ctx);
747         if (MIPS_R6) {
748                 cgen_mips_fp(MIPS_MFC1, MIPS_FP_SINGLE, 0, FR_CMP_RESULT & 31, reg);
749                 if (OP_SIZE_NATIVE > OP_SIZE_4) {
750                         cgen_mips_rot_imm(MIPS_SLL, reg, reg, 0);
751                 }
752                 if (!fp_condition_negated(aux)) {
753                         cgen_mips_3reg(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, reg, R_ZERO, reg);
754                 } else {
755                         cgen_mips_imm(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, reg, reg, 1);
756                 }
757                 return true;
758         } else if (MIPS_HAS_MOVT) {
759                 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
760                 cgen_mips_3reg(!fp_condition_negated(aux) ? MIPS_MOVF : MIPS_MOVT, reg, R_ZERO, 0);
761         } else {
762                 g(cgen_jump_not_last(ctx, 1));
763                 cgen_mips_imm(!fp_condition_negated(aux) ? MIPS_BC1T : MIPS_BC1F, 0, 0, 2);
764                 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
765                 cgen_mips_3reg(MIPS_OR, reg, R_ZERO, R_ZERO);
766         }
767         return true;
770 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
772         uint32_t mc, fmt;
773         uint8_t *arg1 = ctx->code_position;
774         uint8_t *arg2 = arg1 + arg_size(*arg1);
775         uint8_t *arg3 = arg2 + arg_size(*arg2);
776         ctx->code_position = arg3 + arg_size(*arg3);
777         switch (aux) {
778                 case FP_ALU_ADD:        mc = MIPS_ADD_FP; break;
779                 case FP_ALU_SUB:        mc = MIPS_SUB_FP; break;
780                 case FP_ALU_MUL:        mc = MIPS_MUL_FP; break;
781                 case FP_ALU_DIV:        mc = MIPS_DIV_FP; break;
782                 default:                internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
783         }
784         fmt = cgen_fp_fmt(op_size);
785         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
786         return true;
789 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
791         uint32_t mc, fmt;
792         uint8_t *arg1 = ctx->code_position;
793         uint8_t *arg2 = arg1 + arg_size(*arg1);
794         ctx->code_position = arg2 + arg_size(*arg2);
795         switch (aux) {
796                 case FP_ALU1_NEG:       mc = MIPS_NEG_FP; break;
797                 case FP_ALU1_SQRT:      mc = MIPS_SQRT_FP; break;
798                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
799         }
800         fmt = cgen_fp_fmt(op_size);
801         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
802         return true;
805 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
807         uint32_t mc, fmt;
808         uint8_t *arg1 = ctx->code_position;
809         uint8_t *arg2 = arg1 + arg_size(*arg1);
810         ctx->code_position = arg2 + arg_size(*arg2);
811         switch (int_op_size) {
812                 case OP_SIZE_4:         mc = MIPS_TRUNC_W; break;
813                 case OP_SIZE_8:         mc = MIPS_TRUNC_L; break;
814                 default:                internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
815         }
816         fmt = cgen_fp_fmt(fp_op_size);
817         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
818         return true;
821 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
823         uint32_t mc;
824         uint8_t *arg1 = ctx->code_position;
825         uint8_t *arg2 = arg1 + arg_size(*arg1);
826         ctx->code_position = arg2 + arg_size(*arg2);
828         if (int_op_size == OP_SIZE_4) {
829                 if (fp_op_size == OP_SIZE_4)
830                         mc = MIPS_CVT_S_W;
831                 else
832                         mc = MIPS_CVT_D_W;
833         } else {
834                 if (fp_op_size == OP_SIZE_4)
835                         mc = MIPS_CVT_S_L;
836                 else
837                         mc = MIPS_CVT_D_L;
838         }
839         cgen_mips_fp(mc, 0, arg1[0] & 31, arg2[0] & 31, 0);
840         return true;
843 static unsigned cgen_jmp_extra_long_length(void)
845         return !MIPS_R6 ? 6 : 5;
848 static bool attr_w cgen_jmp_extra_long(struct codegen_context *ctx)
850         cgen_mips_imm(MIPS_LUI, R_AT, 0, 0);
851         cgen_mips_imm(MIPS_BGEZAL, 0, R_ZERO, 1);
852         cgen_mips_imm(MIPS_ORI, R_AT, R_AT, 0);
853         cgen_mips_3reg(OP_SIZE_ADDRESS == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, R_AT, R_AT, R_RA);
854         if (!MIPS_R6) {
855                 cgen_mips_3reg(MIPS_JR, 0, R_AT, 0);
856                 cgen_four(MIPS_NOP);
857         } else {
858                 cgen_mips_imm(MIPS_R6_JIC, R_AT, 0, 0);
859         }
860         return true;
863 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
865         if (MIPS_R6 && length <= JMP_LONG) {
866                 g(cgen_jump_not_last(ctx, 1));
867                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
868                 cgen_four(MIPS_R6_BC);
869                 return true;
870         }
871         if (length == JMP_SHORTEST) {
872                 g(cgen_jump_not_last(ctx, 1));
873                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
874                 cgen_mips_imm(MIPS_BEQ, R_ZERO, R_ZERO, 0);
875                 cgen_four(MIPS_NOP);
876                 return true;
877         }
878         g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length()));
879         g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
880         g(cgen_jmp_extra_long(ctx));
881         return true;
884 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
886         uint32_t mc;
887         uint8_t *arg1 = ctx->code_position;
888         ctx->code_position = arg1 + arg_size(*arg1);
890         if (arg1[0] >= 0x20)
891                 goto invalid;
893         if (MIPS_R6 && (cond == COND_E || cond == COND_NE) && length <= JMP_SHORT) {
894                 mc = cond == COND_E ? MIPS_R6_BEQZC : MIPS_R6_BNEZC;
895                 g(cgen_jump_not_last(ctx, 1));
896                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
897                 cgen_four(mc | ((uint32_t)arg1[0] << 21));
898                 cgen_four(MIPS_NOP);
899                 return true;
900         }
902         if (length > JMP_SHORTEST)
903                 cond ^= 1;
905         switch (cond) {
906                 case COND_E:    mc = MIPS_BEQ; break;
907                 case COND_NE:   mc = MIPS_BNE; break;
908                 case COND_S:
909                 case COND_L:    mc = MIPS_BLTZ; break;
910                 case COND_LE:   mc = MIPS_BLEZ; break;
911                 case COND_G:    mc = MIPS_BGTZ; break;
912                 case COND_NS:
913                 case COND_GE:   mc = MIPS_BGEZ; break;
914                 default:        goto invalid;
915         }
917         if (length == JMP_SHORTEST) {
918                 g(cgen_jump_not_last(ctx, 1));
919                 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
920                 cgen_mips_imm(mc, 0, arg1[0], 0);
921                 cgen_four(MIPS_NOP);
922                 return true;
923         }
924         if (MIPS_R6 && length <= JMP_LONG) {
925                 g(cgen_jump_not_last(ctx, 3));
926                 cgen_mips_imm(mc, 0, arg1[0], 2);
927                 cgen_four(MIPS_NOP);
928                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
929                 cgen_four(MIPS_R6_BC);
930                 return true;
931         }
932         g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
933         cgen_mips_imm(mc, 0, arg1[0], cgen_jmp_extra_long_length());
934         g(add_relocation(ctx, JMP_EXTRA_LONG, 1, NULL));
935         g(cgen_jmp_extra_long(ctx));
936         return true;
938 invalid:
939         internal(file_line, "cgen_jmp_reg: invalid arguments %u, %u, %02x", cond, length, arg1[0]);
940         return false;
943 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
945         uint32_t mc;
946         uint8_t *arg1 = ctx->code_position;
947         uint8_t *arg2 = arg1 + arg_size(*arg1);
948         ctx->code_position = arg2 + arg_size(*arg2);
949         if (arg1[0] >= 0x20 || arg2[0] >= 0x20 || (cond != COND_E && cond != COND_NE))
950                 goto invalid;
952         if (length > JMP_SHORTEST)
953                 cond ^= 1;
955         mc = cond == COND_E ? MIPS_BEQ : MIPS_BNE;
957         if (length == JMP_SHORTEST) {
958                 g(cgen_jump_not_last(ctx, 1));
959                 g(add_relocation(ctx, JMP_SHORTEST, 2, NULL));
960                 cgen_mips_imm(mc, arg1[0], arg2[0], 0);
961                 cgen_four(MIPS_NOP);
962                 return true;
963         }
964         if (MIPS_R6 && length <= JMP_LONG) {
965                 g(cgen_jump_not_last(ctx, 3));
966                 cgen_mips_imm(mc, arg1[0], arg2[0], 2);
967                 cgen_four(MIPS_NOP);
968                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
969                 cgen_four(MIPS_R6_BC);
970                 return true;
971         }
972         g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
973         cgen_mips_imm(mc, arg1[0], arg2[0], cgen_jmp_extra_long_length());
974         g(add_relocation(ctx, JMP_EXTRA_LONG, 2, NULL));
975         g(cgen_jmp_extra_long(ctx));
976         return true;
978 invalid:
979         internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
980         return false;
983 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned aux, unsigned length)
985         uint32_t mc;
986         bool t = true;
987         if (fp_condition_negated(aux))
988                 t = !t;
989         if (length > JMP_SHORTEST)
990                 t = !t;
991         if (MIPS_R6) {
992                 mc = t ? MIPS_R6_BC1NEZ : MIPS_R6_BC1EQZ;
993                 if (length == JMP_SHORTEST) {
994                         g(cgen_jump_not_last(ctx, 1));
995                         g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
996                         cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 0);
997                         cgen_four(MIPS_NOP);
998                         return true;
999                 }
1000                 if (length <= JMP_LONG) {
1001                         g(cgen_jump_not_last(ctx, 3));
1002                         cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 2);
1003                         cgen_four(MIPS_NOP);
1004                         g(add_relocation(ctx, JMP_LONG, 0, NULL));
1005                         cgen_four(MIPS_R6_BC);
1006                         return true;
1007                 }
1008                 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1009                 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, cgen_jmp_extra_long_length());
1010                 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1011                 g(cgen_jmp_extra_long(ctx));
1012                 return true;
1013         } else {
1014                 mc = t ? MIPS_BC1T : MIPS_BC1F;
1015                 if (length == JMP_SHORTEST) {
1016                         g(cgen_jump_not_last(ctx, 1));
1017                         g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1018                         cgen_mips_imm(mc, 0, 0, 0);
1019                         cgen_four(MIPS_NOP);
1020                         return true;
1021                 }
1022                 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1023                 cgen_mips_imm(mc, 0, 0, cgen_jmp_extra_long_length());
1024                 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1025                 g(cgen_jmp_extra_long(ctx));
1026                 return true;
1027         }
1030 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, unsigned reg, bool call)
1032         g(cgen_jump_not_last(ctx, 1));
1033         if (!call) {
1034                 if (!MIPS_R6) {
1035                         cgen_mips_3reg(MIPS_JR, 0, reg, 0);
1036                         cgen_four(MIPS_NOP);
1037                 } else {
1038                         cgen_mips_imm(MIPS_R6_JIC, reg, 0, 0);
1039                 }
1040         } else {
1041                 if (!MIPS_R6) {
1042                         cgen_mips_3reg(MIPS_JALR, R_RA, reg, 0);
1043                         cgen_four(MIPS_NOP);
1044                 } else {
1045                         cgen_mips_imm(MIPS_R6_JIALC, reg, 0, 0);
1046                 }
1047         }
1048         return true;
1052 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1054         uint32_t mc;
1055         int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1056         switch (reloc->length) {
1057                 case JMP_SHORTEST:
1058                         offs /= 4;
1059                         offs--;
1060                         if (offs != (int16_t)offs)
1061                                 return false;
1062                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1063                         mc &= ~0xFFFFU;
1064                         mc |= offs & 0xFFFFU;
1065                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1066                         return true;
1067                 case JMP_SHORT:
1068                         offs /= 4;
1069                         offs--;
1070                         if (offs < -0x00100000 || offs >= 0x00100000)
1071                                 return false;
1072                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1073                         mc &= ~0x001FFFFFU;
1074                         mc |= offs & 0x001FFFFFU;
1075                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1076                         return true;
1077                 case JMP_LONG:
1078                         offs /= 4;
1079                         offs--;
1080                         if (offs < -0x02000000 || offs >= 0x02000000)
1081                                 return false;
1082                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1083                         mc &= ~0x03FFFFFFU;
1084                         mc |= offs & 0x03FFFFFFU;
1085                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1086                         return true;
1087                 case JMP_EXTRA_LONG:
1088                         offs -= 12;
1089                         if (offs != (int32_t)offs)
1090                                 return false;
1091                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1092                         mc &= ~0xFFFFU;
1093                         mc |= ((uint64_t)offs >> 16) & 0xFFFFU;
1094                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1095                         memcpy(&mc, ctx->mcode + reloc->position + 8, 4);
1096                         mc &= ~0xFFFFU;
1097                         mc |= offs & 0xFFFFU;
1098                         memcpy(ctx->mcode + reloc->position + 8, &mc, 4);
1099                         return true;
1100                 default:
1101                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1102         }
1103         return false;
1107 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1109         if (unlikely(insn_writes_flags(insn))) {
1110                 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
1111                         goto invalid_insn;
1112         }
1113         switch (insn_opcode(insn)) {
1114                 case INSN_ENTRY:
1115                         g(cgen_entry(ctx));
1116                         return true;
1117                 case INSN_LABEL:
1118                         g(cgen_label(ctx));
1119                         return true;
1120                 case INSN_RET:
1121                         g(cgen_jmp_call_indirect(ctx, R_RA, false));
1122                         if (MIPS_R6)
1123                                 cgen_four(MIPS_NOP);
1124                         return true;
1125                 case INSN_CALL_INDIRECT:
1126                         g(cgen_jmp_call_indirect(ctx, cget_one(ctx), true));
1127                         return true;
1128                 case INSN_MOV:
1129                         g(cgen_mov(ctx, insn_op_size(insn), false));
1130                         return true;
1131                 case INSN_MOVSX:
1132                         g(cgen_mov(ctx, insn_op_size(insn), true));
1133                         return true;
1134                 case INSN_MOV_LR:
1135                         g(cgen_mov_lr(ctx, insn_op_size(insn), insn_aux(insn) != 0));
1136                         return true;
1137                 case INSN_CMP_DEST_REG:
1138                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1139                                 goto invalid_insn;
1140                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
1141                         return true;
1142                 case INSN_ALU:
1143                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1144                                 goto invalid_insn;
1145                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), false));
1146                         return true;
1147                 case INSN_ALU_TRAP:
1148                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1149                                 goto invalid_insn;
1150                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), true));
1151                         return true;
1152                 case INSN_ALU1:
1153                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1154                                 goto invalid_insn;
1155                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
1156                         return true;
1157                 case INSN_ALU1_TRAP:
1158                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1159                                 goto invalid_insn;
1160                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
1161                         return true;
1162                 case INSN_ROT:
1163                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1164                                 goto invalid_insn;
1165                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
1166                         return true;
1167                 case INSN_MUL_L:
1168                         if (unlikely(insn_op_size(insn) <= OP_SIZE_2) || unlikely(insn_op_size(insn) > OP_SIZE_NATIVE))
1169                                 goto invalid_insn;
1170                         g(cgen_mul_l(ctx, insn_op_size(insn)));
1171                         return true;
1172                 case INSN_FP_CMP_COND:
1173                         g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
1174                         return true;
1175                 case INSN_FP_TEST_REG:
1176                         g(cgen_fp_test_reg(ctx, insn_aux(insn)));
1177                         return true;
1178                 case INSN_FP_ALU:
1179                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1180                         return true;
1181                 case INSN_FP_ALU1:
1182                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1183                         return true;
1184                 case INSN_FP_TO_INT32:
1185                 case INSN_FP_TO_INT64:
1186                         g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1187                         return true;
1188                 case INSN_FP_FROM_INT32:
1189                 case INSN_FP_FROM_INT64:
1190                         g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1191                         return true;
1192                 case INSN_JMP:
1193                         g(cgen_jmp(ctx, insn_jump_size(insn)));
1194                         return true;
1195                 case INSN_JMP_REG:
1196                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1197                         return true;
1198                 case INSN_JMP_2REGS:
1199                         g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
1200                         return true;
1201                 case INSN_JMP_FP_TEST:
1202                         g(cgen_jmp_fp_test(ctx, insn_aux(insn), insn_jump_size(insn)));
1203                         return true;
1204                 case INSN_JMP_INDIRECT:
1205                         g(cgen_jmp_call_indirect(ctx, cget_one(ctx), false));
1206                         return true;
1207                 default:
1208                 invalid_insn:
1209                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
1210                         return false;
1211         }