codegen: fix bug on riscv when --ptrcomp was used
[ajla.git] / c2-mips.inc
blob5b8a8ce674b8e797b145128e366d22a4a6b07954
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_AUI             0x3c000000U
172 #define MIPS_R6_BC1EQZ          0x45200000U
173 #define MIPS_R6_BC1NEZ          0x45a00000U
174 #define MIPS_R6_CMP_AF          0x46800000U
175 #define MIPS_R6_CMP_UN          0x46800001U
176 #define MIPS_R6_CMP_EQ          0x46800002U
177 #define MIPS_R6_CMP_UEQ         0x46800003U
178 #define MIPS_R6_CMP_LT          0x46800004U
179 #define MIPS_R6_CMP_ULT         0x46800005U
180 #define MIPS_R6_CMP_LE          0x46800006U
181 #define MIPS_R6_CMP_ULE         0x46800007U
182 #define MIPS_R6_CMP_OR          0x46800011U
183 #define MIPS_R6_CMP_UNE         0x46800012U
184 #define MIPS_R6_CMP_NE          0x46800013U
185 #define MIPS_R6_BGEZC           0x58000000U
186 #define MIPS_R6_BLEZC           0x58000000U
187 #define MIPS_R6_BGTZC           0x5c000000U
188 #define MIPS_R6_BLTZC           0x5c000000U
189 #define MIPS_R6_DAUI            0x74000000U
190 #define MIPS_R6_BITSWAP         0x7c000020U
191 #define MIPS_R6_DBITSWAP        0x7c000024U
192 #define MIPS_R6_BC              0xc8000000U
193 #define MIPS_R6_JIC             0xd8000000U
194 #define MIPS_R6_BEQZC           0xd8000000U
195 #define MIPS_R6_JIALC           0xf8000000U
196 #define MIPS_R6_BNEZC           0xf8000000U
198 #define cgen_mips_3reg(mc, rd, rs, rt) \
199         cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rs) << 21) | ((uint32_t)(rt) << 16))
200 #define cgen_mips_rot_imm(mc, rd, rt, sa) \
201         cgen_four((mc) | ((uint32_t)(rd) << 11) | ((uint32_t)(rt) << 16) | (((sa) & 0x1f) << 6))
202 #define cgen_mips_imm(mc, rt, rs, imm) \
203         cgen_four((mc) | ((uint32_t)(rt) << 16) | ((uint32_t)(rs) << 21) | ((imm) & 0xffff))
204 #define cgen_mips_fp(mc, fmt, fd, fs, ft) \
205         cgen_four((mc) | ((uint32_t)(fmt) << 21) | ((uint32_t)(fd) << 6) | ((uint32_t)(fs) << 11) | ((uint32_t)(ft) << 16))
207 static bool attr_w cgen_jump_not_last(struct codegen_context *ctx, unsigned insns)
209         if (MIPS_R4000_ERRATA) {
210                 while (unlikely((ctx->mcode_size & 0xfffU) + insns * 4 >= 0x1000U)) {
211                         cgen_four(MIPS_NOP);
212                 }
213         }
214         return true;
217 static bool attr_w cgen_ls(struct codegen_context *ctx, uint32_t mc, uint8_t arg1, uint8_t *arg2)
219         int64_t imm = get_imm(&arg2[2]);
220         if (unlikely(imm != (int16_t)imm))
221                 internal(file_line, "cgen_ls: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
222         cgen_mips_imm(mc, arg1, arg2[1], imm);
223         return true;
226 static uint32_t cgen_fp_fmt(unsigned op_size)
228         switch (op_size) {
229                 case OP_SIZE_4:         return MIPS_FP_SINGLE;
230                 case OP_SIZE_8:         return MIPS_FP_DOUBLE;
231                 default:                internal(file_line, "cgen_fp_fmt: invalid size %u", op_size);
232                                         return -1U;
233         }
236 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
238         int64_t imm;
239         uint8_t z = R_ZERO;
240         uint8_t *arg1 = ctx->code_position;
241         uint8_t *arg2 = arg1 + arg_size(*arg1);
242         ctx->code_position = arg2 + arg_size(*arg2);
243         if (arg1[0] < 32) {
244                 if (arg2[0] < 32) {
245                         if (sx && size == OP_SIZE_1) {
246                                 cgen_mips_3reg(MIPS_SEB, arg1[0], 0, arg2[0]);
247                                 return true;
248                         }
249                         if (sx && size == OP_SIZE_2) {
250                                 cgen_mips_3reg(MIPS_SEH, arg1[0], 0, arg2[0]);
251                                 return true;
252                         }
253                         if (unlikely(size != OP_SIZE_NATIVE))
254                                 internal(file_line, "cgen_mov: unsupported size %u", size);
255                         cgen_mips_3reg(MIPS_OR, arg1[0], arg2[0], R_ZERO);
256                         return true;
257                 }
258                 if (reg_is_fp(arg2[0])) {
259                         uint32_t fmt = cgen_fp_fmt(size);
260                         cgen_mips_fp(MIPS_MFC1, fmt, 0, arg2[0] & 31, arg1[0]);
261                         return true;
262                 }
263                 if (arg2[0] == ARG_IMM) {
264                         imm = get_imm(&arg2[1]);
265                         if (unlikely((imm & 0xffff) != 0) || unlikely(imm != (int32_t)imm))
266                                 internal(file_line, "cgen_mov: invalid imm: %"PRIxMAX"", (uintmax_t)imm);
267                         cgen_mips_imm(MIPS_LUI, arg1[0], 0, (uint64_t)imm >> 16);
268                         return true;
269                 }
270                 if (arg2[0] == ARG_ADDRESS_1) {
271                         if (!sx && size != OP_SIZE_NATIVE)
272                                 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LBU : size == OP_SIZE_2 ? MIPS_LHU : MIPS_LWU, arg1[0], arg2));
273                         else
274                                 g(cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_LB : size == OP_SIZE_2 ? MIPS_LH : size == OP_SIZE_4 ? MIPS_LW : MIPS_LD, arg1[0], arg2));
275                         if (MIPS_LOAD_DELAY_SLOTS)
276                                 cgen_four(MIPS_NOP);
277                         return true;
278                 }
279                 goto invalid;
280         }
281         if (reg_is_fp(arg1[0])) {
282                 if (arg2[0] < 32) {
283                         uint32_t fmt = cgen_fp_fmt(size);
284                         cgen_mips_fp(MIPS_MTC1, fmt, 0, arg1[0] & 31, arg2[0]);
285                         return true;
286                 }
287                 if (reg_is_fp(arg2[0])) {
288                         uint32_t fmt = cgen_fp_fmt(size);
289                         uint32_t mc = MIPS_MOV_FP;
290                         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
291                         return true;
292                 }
293                 g(cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_LWC1 : MIPS_LDC1, arg1[0] & 31, arg2));
294                 if (MIPS_LOAD_DELAY_SLOTS)
295                         cgen_four(MIPS_NOP);
296                 return true;
297         }
298         if (arg1[0] == ARG_ADDRESS_1) {
299                 if (arg2[0] == ARG_IMM) {
300                         imm = get_imm(&arg2[1]);
301                         if (unlikely(imm != 0))
302                                 goto invalid;
303                         arg2 = &z;
304                 }
305                 if (arg2[0] < 32) {
306                         return cgen_ls(ctx, size == OP_SIZE_1 ? MIPS_SB : size == OP_SIZE_2 ? MIPS_SH : size == OP_SIZE_4 ? MIPS_SW : MIPS_SD, arg2[0], arg1);
307                 }
308                 if (reg_is_fp(arg2[0])) {
309                         return cgen_ls(ctx, size == OP_SIZE_4 ? MIPS_SWC1 : MIPS_SDC1, arg2[0] & 31, arg1);
310                 }
311                 goto invalid;
312         }
314 invalid:
315         internal(file_line, "cgen_mov: invalid arguments %02x, %02x, %u, %u", arg1[0], arg2[0], size, (unsigned)sx);
316         return false;
319 static bool attr_w cgen_mov_lr(struct codegen_context *ctx, unsigned size, bool r)
321         int64_t imm;
322         uint32_t mc;
323         uint8_t *arg1, *arg2, *arg3;
324         arg1 = ctx->code_position;
325         arg2 = arg1 + arg_size(*arg1);
326         arg3 = arg2 + arg_size(*arg2);
327         ctx->code_position = arg3 + arg_size(*arg3);
329         if (unlikely(arg1[0] != arg2[0]))
330                 goto invalid;
332         if (arg1[0] < 32 && arg3[0] == ARG_ADDRESS_1) {
333                 imm = get_imm(&arg3[2]);
334                 if (!r)
335                         mc = size == OP_SIZE_4 ? MIPS_LWL : MIPS_LDL;
336                 else
337                         mc = size == OP_SIZE_4 ? MIPS_LWR : MIPS_LDR;
338                 cgen_mips_imm(mc, arg1[0], arg3[1], imm);
339                 if (MIPS_LOAD_DELAY_SLOTS)
340                         cgen_four(MIPS_NOP);
341                 return true;
342         } if (arg1[0] == ARG_ADDRESS_1 && arg3[0] < 32) {
343                 imm = get_imm(&arg1[2]);
344                 if (!r)
345                         mc = size == OP_SIZE_4 ? MIPS_SWL : MIPS_SDL;
346                 else
347                         mc = size == OP_SIZE_4 ? MIPS_SWR : MIPS_SDR;
348                 cgen_mips_imm(mc, arg3[0], arg1[1], imm);
349                 return true;
350         }
352 invalid:
353         internal(file_line, "cgen_mov_lr: invalid parameters %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
354         return false;
357 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
359         uint32_t mc;
360         bool swap = false;
361         uint8_t z = R_ZERO;
362         uint8_t *arg1 = ctx->code_position;
363         uint8_t *arg2 = arg1 + arg_size(*arg1);
364         uint8_t *arg3 = arg2 + arg_size(*arg2);
365         ctx->code_position = arg3 + arg_size(*arg3);
366         if (arg3[0] == ARG_IMM) {
367                 int64_t imm = get_imm(&arg3[1]);
368                 if (unlikely(imm != (int16_t)imm))
369                         internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
370                 switch (aux) {
371                         case COND_B:    mc = MIPS_SLTIU; break;
372                         case COND_L:    mc = MIPS_SLTI; break;
373                         default:        goto invalid;
374                 }
375                 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
376                 return true;
377         }
378         if (arg2[0] == ARG_IMM) {
379                 int64_t imm = get_imm(&arg2[1]);
380                 if (unlikely(imm != 0))
381                         internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
382                 arg2 = &z;
383         }
384         switch (aux) {
385                 case COND_B:    mc = MIPS_SLTU; break;
386                 case COND_A:    mc = MIPS_SLTU; swap = true; break;
387                 case COND_L:    mc = MIPS_SLT; break;
388                 case COND_G:    mc = MIPS_SLT; swap = true; break;
389                 default:        goto invalid;
390         }
391         if (swap) {
392                 uint8_t *argx = arg2;
393                 arg2 = arg3;
394                 arg3 = argx;
395         }
396         cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
397         return true;
399 invalid:
400         internal(file_line, "cgen_cmp_dest_reg: invalid arguments %u, %02x, %02x, %02x", aux, arg1[0], arg2[0], arg3[0]);
401         return false;
404 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
406         uint32_t mc;
407         int64_t imm = 0;
408         bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
409         uint8_t *arg1 = ctx->code_position;
410         uint8_t *arg2 = arg1 + arg_size(*arg1);
411         uint8_t *arg3 = arg2 + arg_size(*arg2);
412         ctx->code_position = arg3 + arg_size(*arg3);
414         if (alu == ALU_ADD && arg2[0] == ARG_SHIFTED_REGISTER) {
415                 uint8_t *arg_swp = arg3;
416                 arg3 = arg2;
417                 arg2 = arg_swp;
418         }
419         if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
420                 uint32_t shift;
421                 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL))
422                         goto invalid;
423                 shift = arg3[1] & ARG_SHIFT_AMOUNT;
424                 if (unlikely(shift < 1) || unlikely(shift > 4))
425                         goto invalid;
426                 mc = size == OP_SIZE_8 ? MIPS_R6_DLSA : MIPS_R6_LSA;
427                 mc |= (shift - 1) << 6;
428                 cgen_mips_3reg(mc, arg1[0], arg3[2], arg2[0]);
429                 return true;
430         }
432         if ((alu == ALU_ADD || alu == ALU_SUB) && arg3[0] == ARG_IMM && trap && !have_imm_trap) {
433                 imm = get_imm(&arg3[1]);
434                 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, imm);
435                 g(cgen_trap(ctx, cget_four(ctx)));
436                 if (alu == ALU_ADD)
437                         mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
438                 else
439                         mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
440                 cgen_mips_3reg(mc, arg1[0], arg2[0], R_AT);
441                 return true;
442         }
443         if (MIPS_R6 && alu == ALU_ADD && arg3[0] == ARG_IMM && !trap) {
444                 imm = get_imm(&arg3[1]);
445                 if (imm && !(imm & 0xffff)) {
446                         if (imm == (int32_t)imm) {
447                                 cgen_mips_imm(size == OP_SIZE_4 ? MIPS_R6_AUI : MIPS_R6_DAUI, arg1[0], arg2[0], (uint64_t)imm >> 16);
448                                 return true;
449                         }
450                         if (imm & 0xFFFFFFFFLL)
451                                 goto invalid;
452                         imm /= 0x100000000LL;
453                         if (imm == (int16_t)imm && size == OP_SIZE_8) {
454                                 if (unlikely(arg1[0] != arg2[0]))
455                                         goto invalid;
456                                 cgen_mips_imm(MIPS_R6_DAHI, 0, arg1[0], imm);
457                                 return true;
458                         }
459                         if (imm & 0xFFFFLL)
460                                 goto invalid;
461                         imm /= 0x10000LL;
462                         if (size == OP_SIZE_8) {
463                                 if (unlikely(arg1[0] != arg2[0]))
464                                         goto invalid;
465                                 cgen_mips_imm(MIPS_R6_DATI, 0, arg1[0], imm);
466                                 return true;
467                         }
468                         goto invalid;
469                 }
470         }
472         if (trap)
473                 g(cgen_trap(ctx, cget_four(ctx)));
475         switch (alu) {
476                 case ALU_MUL:
477                         if (MIPS_R6) {
478                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUL : MIPS_R6_DMUL, arg1[0], arg2[0], arg3[0]);
479                                 return true;
480                         }
481                         if (size == OP_SIZE_4 && MIPS_HAS_MUL) {
482                                 cgen_mips_3reg(MIPS_MUL, arg1[0], arg2[0], arg3[0]);
483                                 return true;
484                         }
485                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
486                         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
487                         return true;
488                 case ALU_UMULH:
489                         if (MIPS_R6) {
490                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUHU : MIPS_R6_DMUHU, arg1[0], arg2[0], arg3[0]);
491                                 return true;
492                         }
493                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULTU : MIPS_DMULTU, 0, arg2[0], arg3[0]);
494                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
495                         return true;
496                 case ALU_SMULH:
497                         if (MIPS_R6) {
498                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MUH : MIPS_R6_DMUH, arg1[0], arg2[0], arg3[0]);
499                                 return true;
500                         }
501                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg2[0], arg3[0]);
502                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
503                         return true;
504                 case ALU_UDIV:
505                         if (MIPS_R6) {
506                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIVU : MIPS_R6_DDIVU, arg1[0], arg2[0], arg3[0]);
507                                 return true;
508                         }
509                         g(cgen_jump_not_last(ctx, 1));
510                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
511                         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
512                         return true;
513                 case ALU_SDIV:
514                         if (MIPS_R6) {
515                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_DIV : MIPS_R6_DDIV, arg1[0], arg2[0], arg3[0]);
516                                 return true;
517                         }
518                         g(cgen_jump_not_last(ctx, 1));
519                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
520                         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
521                         return true;
522                 case ALU_UREM:
523                         if (MIPS_R6) {
524                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MODU : MIPS_R6_DMODU, arg1[0], arg2[0], arg3[0]);
525                                 return true;
526                         }
527                         g(cgen_jump_not_last(ctx, 1));
528                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIVU : MIPS_DDIVU, 0, arg2[0], arg3[0]);
529                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
530                         return true;
531                 case ALU_SREM:
532                         if (MIPS_R6) {
533                                 cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_R6_MOD : MIPS_R6_DMOD, arg1[0], arg2[0], arg3[0]);
534                                 return true;
535                         }
536                         g(cgen_jump_not_last(ctx, 1));
537                         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_DIV : MIPS_DDIV, 0, arg2[0], arg3[0]);
538                         cgen_mips_3reg(MIPS_MFHI, arg1[0], 0, 0);
539                         return true;
540         }
542         if (arg3[0] == ARG_IMM) {
543                 imm = get_imm(&arg3[1]);
544                 if (alu == ALU_SUB) {
545                         imm = -(uint64_t)imm;
546                         alu = ALU_ADD;
547                 }
548                 switch (alu) {
549                         case ALU_ADD:   if (trap) mc = size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI;
550                                         else mc = size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU;
551                                         break;
552                         case ALU_XOR:   mc = MIPS_XORI; break;
553                         case ALU_OR:    mc = MIPS_ORI; break;
554                         case ALU_AND:   mc = MIPS_ANDI; break;
555                         default:        goto invalid;
556                 }
557                 if (unlikely(imm != (alu == ALU_ADD ? (int64_t)(int16_t)imm : (int64_t)(uint16_t)imm)))
558                         internal(file_line, "cgen_alu: invalid imm: %"PRIxMAX" (%u)", (uintmax_t)imm, alu);
559                 cgen_mips_imm(mc, arg1[0], arg2[0], imm);
560                 return true;
561         }
563         switch (alu) {
564                 case ALU_ADD:   if (trap) mc = size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD;
565                                 else mc = size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU;
566                                 break;
567                 case ALU_SUB:   if (trap) mc = size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB;
568                                 else mc = size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU;
569                                 break;
570                 case ALU_XOR:   mc = MIPS_XOR; break;
571                 case ALU_OR:    mc = MIPS_OR; break;
572                 case ALU_AND:   mc = MIPS_AND; break;
573                 default:        goto invalid;
574         }
575         cgen_mips_3reg(mc, arg1[0], arg2[0], arg3[0]);
576         return true;
578 invalid:
579         internal(file_line, "cgen_alu: invalid alu %u, %u, %"PRIxMAX"", size, alu, (uintmax_t)imm);
580         return false;
583 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, bool trap)
585         bool have_imm_trap = !MIPS_R6 && !(size == OP_SIZE_8 && MIPS_R4000_ERRATA); /* R4000 has broken DADDI */
586         int cnst = alu == ALU1_INC ? 1 : alu == ALU1_DEC ? -1 : 0;
587         uint8_t *arg1 = ctx->code_position;
588         uint8_t *arg2 = arg1 + arg_size(*arg1);
589         ctx->code_position = arg2 + arg_size(*arg2);
591         if (cnst && trap && !have_imm_trap) {
592                 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
593                 g(cgen_trap(ctx, cget_four(ctx)));
594                 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADD : MIPS_ADD, arg1[0], arg2[0], R_AT);
595                 return true;
596         }
597         if (MIPS_R4000_ERRATA && cnst && !trap && size == OP_SIZE_8) {  /* R4000 has broken DADDIU */
598                 cgen_mips_imm(MIPS_ADDIU, R_AT, R_ZERO, cnst);
599                 cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, arg1[0], arg2[0], R_AT);
600                 return true;
601         }
603         if (trap)
604                 g(cgen_trap(ctx, cget_four(ctx)));
606         switch (alu) {
607                 case ALU1_NOT:  cgen_mips_3reg(MIPS_NOR, arg1[0], R_ZERO, arg2[0]);
608                                 return true;
609                 case ALU1_NEG:  if (trap) cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DSUB : MIPS_SUB, arg1[0], R_ZERO, arg2[0]);
610                                 else cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, arg1[0], R_ZERO, arg2[0]);
611                                 return true;
612                 case ALU1_INC:
613                 case ALU1_DEC:  if (trap) cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDI : MIPS_ADDI, arg1[0], arg2[0], cnst);
614                                 else cgen_mips_imm(size == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, arg1[0], arg2[0], cnst);
615                                 return true;
616                 case ALU1_LZCNT: if (!MIPS_R6)
617                                         cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_DCLZ : MIPS_CLZ, arg1[0], arg2[0], arg1[0]);
618                                 else
619                                         cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DCLZ : MIPS_R6_CLZ, arg1[0], arg2[0], 0);
620                                 return true;
621                 case ALU1_BSWAP:
622                 bswap:          if (size == OP_SIZE_4) {
623                                         cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
624                                         cgen_mips_rot_imm(MIPS_ROTR, arg1[0], arg1[0], 16);
625                                 } else {
626                                         cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
627                                         cgen_mips_3reg(MIPS_DSHD, arg1[0], 0, arg1[0]);
628                                 }
629                                 return true;
630                 case ALU1_BSWAP16:if (size == OP_SIZE_4) {
631                                         cgen_mips_3reg(MIPS_WSBH, arg1[0], 0, arg2[0]);
632                                 } else {
633                                         cgen_mips_3reg(MIPS_DSBH, arg1[0], 0, arg2[0]);
634                                 }
635                                 return true;
636                 case ALU1_BREV: cgen_mips_3reg(size == OP_SIZE_8 ? MIPS_R6_DBITSWAP : MIPS_R6_BITSWAP, arg1[0], 0, arg2[0]);
637                                 arg2 = arg1;
638                                 goto bswap;
639                 default:        goto invalid;
640         }
642 invalid:
643         internal(file_line, "cgen_alu1: invalid alu %u, %u", size, alu);
644         return false;
647 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
649         uint32_t mc;
650         uint8_t *arg1 = ctx->code_position;
651         uint8_t *arg2 = arg1 + arg_size(*arg1);
652         uint8_t *arg3 = arg2 + arg_size(*arg2);
653         ctx->code_position = arg3 + arg_size(*arg3);
655         if (arg3[0] == ARG_IMM) {
656                 int64_t imm = get_imm(&arg3[1]);
657                 switch (alu) {
658                         case ROT_SHL:   mc = size == OP_SIZE_4 ? MIPS_SLL : imm & 0x20 ? MIPS_DSLL32 : MIPS_DSLL; break;
659                         case ROT_SHR:   mc = size == OP_SIZE_4 ? MIPS_SRL : imm & 0x20 ? MIPS_DSRL32 : MIPS_DSRL; break;
660                         case ROT_SAR:   mc = size == OP_SIZE_4 ? MIPS_SRA : imm & 0x20 ? MIPS_DSRA32 : MIPS_DSRA; break;
661                         case ROT_ROR:   mc = size == OP_SIZE_4 ? MIPS_ROTR : imm & 0x20 ? MIPS_DROTR32 : MIPS_DROTR; break;
662                         default:        goto invalid;
663                 }
664                 cgen_mips_rot_imm(mc, arg1[0], arg2[0], imm);
665                 return true;
666         } else {
667                 switch (alu) {
668                         case ROT_SHL:   mc = size == OP_SIZE_4 ? MIPS_SLLV : MIPS_DSLLV; break;
669                         case ROT_SHR:   mc = size == OP_SIZE_4 ? MIPS_SRLV : MIPS_DSRLV; break;
670                         case ROT_SAR:   mc = size == OP_SIZE_4 ? MIPS_SRAV : MIPS_DSRAV; break;
671                         case ROT_ROR:   mc = size == OP_SIZE_4 ? MIPS_ROTRV : MIPS_DROTRV; break;
672                         default:        goto invalid;
673                 }
674                 cgen_mips_3reg(mc, arg1[0], arg3[0], arg2[0]);
675                 return true;
676         }
678 invalid:
679         internal(file_line, "cgen_rot: invalid rotation %u, %u", size, alu);
680         return false;
683 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size)
685         uint8_t *arg1, *arg2, *arg3, *arg4;
686         arg1 = ctx->code_position;
687         arg2 = arg1 + arg_size(*arg1);
688         arg3 = arg2 + arg_size(*arg2);
689         arg4 = arg3 + arg_size(*arg3);
690         ctx->code_position = arg4 + arg_size(*arg4);
692         cgen_mips_3reg(size == OP_SIZE_4 ? MIPS_MULT : MIPS_DMULT, 0, arg3[0], arg4[0]);
693         cgen_mips_3reg(MIPS_MFLO, arg1[0], 0, 0);
694         cgen_mips_3reg(MIPS_MFHI, arg2[0], 0, 0);
696         return true;
699 static bool fp_condition_negated(unsigned aux)
701         switch (aux) {
702                 case FP_COND_P:         return false;
703                 case FP_COND_E:         return false;
704                 case FP_COND_B:         return false;
705                 case FP_COND_BE:        return false;
706                 case FP_COND_NP:        return true;
707                 case FP_COND_NE:        return true;
708                 case FP_COND_AE:        return true;
709                 case FP_COND_A:         return true;
710                 default:                internal(file_line, "fp_condition_negated: invalid condition %u", aux);
711         }
712         return false;
715 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
717         uint32_t mc, fmt;
718         uint8_t *arg1 = ctx->code_position;
719         uint8_t *arg2 = arg1 + arg_size(*arg1);
720         ctx->code_position = arg2 + arg_size(*arg2);
722         if (MIPS_R6) {
723                 switch (aux) {
724                         case FP_COND_P:         mc = MIPS_R6_CMP_UN; break;
725                         case FP_COND_E:         mc = MIPS_R6_CMP_EQ; break;
726                         case FP_COND_B:         mc = MIPS_R6_CMP_LT; break;
727                         case FP_COND_BE:        mc = MIPS_R6_CMP_LE; break;
728                         case FP_COND_NP:        mc = MIPS_R6_CMP_UN; break;
729                         case FP_COND_NE:        mc = MIPS_R6_CMP_EQ; break;
730                         case FP_COND_AE:        mc = MIPS_R6_CMP_LT; break;
731                         case FP_COND_A:         mc = MIPS_R6_CMP_LE; break;
732                         default:                internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
733                                                 return false;
734                 }
735         } else {
736                 switch (aux) {
737                         case FP_COND_P:         mc = MIPS_C_UN; break;
738                         case FP_COND_E:         mc = MIPS_C_EQ; break;
739                         case FP_COND_B:         mc = MIPS_C_OLT; break;
740                         case FP_COND_BE:        mc = MIPS_C_OLE; break;
741                         case FP_COND_NP:        mc = MIPS_C_UN; break;
742                         case FP_COND_NE:        mc = MIPS_C_EQ; break;
743                         case FP_COND_AE:        mc = MIPS_C_OLT; break;
744                         case FP_COND_A:         mc = MIPS_C_OLE; break;
745                         default:                internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
746                                                 return false;
747                 }
748         }
749         fmt = cgen_fp_fmt(op_size);
750         cgen_mips_fp(mc, fmt, MIPS_R6 ? FR_CMP_RESULT & 31 : 0, arg1[0] & 31, arg2[0] & 31);
751         if (MIPS_FCMP_DELAY_SLOTS)
752                 cgen_four(MIPS_NOP);
753         return true;
756 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx, unsigned aux)
758         unsigned reg = cget_one(ctx);
759         if (MIPS_R6) {
760                 cgen_mips_fp(MIPS_MFC1, MIPS_FP_SINGLE, 0, FR_CMP_RESULT & 31, reg);
761                 if (OP_SIZE_NATIVE > OP_SIZE_4) {
762                         cgen_mips_rot_imm(MIPS_SLL, reg, reg, 0);
763                 }
764                 if (!fp_condition_negated(aux)) {
765                         cgen_mips_3reg(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DSUBU : MIPS_SUBU, reg, R_ZERO, reg);
766                 } else {
767                         cgen_mips_imm(OP_SIZE_NATIVE == OP_SIZE_8 ? MIPS_DADDIU : MIPS_ADDIU, reg, reg, 1);
768                 }
769                 return true;
770         } else if (MIPS_HAS_MOVT) {
771                 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
772                 cgen_mips_3reg(!fp_condition_negated(aux) ? MIPS_MOVF : MIPS_MOVT, reg, R_ZERO, 0);
773         } else {
774                 g(cgen_jump_not_last(ctx, 1));
775                 cgen_mips_imm(!fp_condition_negated(aux) ? MIPS_BC1T : MIPS_BC1F, 0, 0, 2);
776                 cgen_mips_imm(MIPS_ORI, reg, R_ZERO, 1);
777                 cgen_mips_3reg(MIPS_OR, reg, R_ZERO, R_ZERO);
778         }
779         return true;
782 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
784         uint32_t mc, fmt;
785         uint8_t *arg1 = ctx->code_position;
786         uint8_t *arg2 = arg1 + arg_size(*arg1);
787         uint8_t *arg3 = arg2 + arg_size(*arg2);
788         ctx->code_position = arg3 + arg_size(*arg3);
789         switch (aux) {
790                 case FP_ALU_ADD:        mc = MIPS_ADD_FP; break;
791                 case FP_ALU_SUB:        mc = MIPS_SUB_FP; break;
792                 case FP_ALU_MUL:        mc = MIPS_MUL_FP; break;
793                 case FP_ALU_DIV:        mc = MIPS_DIV_FP; break;
794                 default:                internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
795         }
796         fmt = cgen_fp_fmt(op_size);
797         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
798         return true;
801 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
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 (aux) {
808                 case FP_ALU1_NEG:       mc = MIPS_NEG_FP; break;
809                 case FP_ALU1_SQRT:      mc = MIPS_SQRT_FP; break;
810                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
811         }
812         fmt = cgen_fp_fmt(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_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
819         uint32_t mc, fmt;
820         uint8_t *arg1 = ctx->code_position;
821         uint8_t *arg2 = arg1 + arg_size(*arg1);
822         ctx->code_position = arg2 + arg_size(*arg2);
823         switch (int_op_size) {
824                 case OP_SIZE_4:         mc = MIPS_TRUNC_W; break;
825                 case OP_SIZE_8:         mc = MIPS_TRUNC_L; break;
826                 default:                internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
827         }
828         fmt = cgen_fp_fmt(fp_op_size);
829         cgen_mips_fp(mc, fmt, arg1[0] & 31, arg2[0] & 31, 0);
830         return true;
833 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
835         uint32_t mc;
836         uint8_t *arg1 = ctx->code_position;
837         uint8_t *arg2 = arg1 + arg_size(*arg1);
838         ctx->code_position = arg2 + arg_size(*arg2);
840         if (int_op_size == OP_SIZE_4) {
841                 if (fp_op_size == OP_SIZE_4)
842                         mc = MIPS_CVT_S_W;
843                 else
844                         mc = MIPS_CVT_D_W;
845         } else {
846                 if (fp_op_size == OP_SIZE_4)
847                         mc = MIPS_CVT_S_L;
848                 else
849                         mc = MIPS_CVT_D_L;
850         }
851         cgen_mips_fp(mc, 0, arg1[0] & 31, arg2[0] & 31, 0);
852         return true;
855 static unsigned cgen_jmp_extra_long_length(void)
857         return !MIPS_R6 ? 6 : 5;
860 static bool attr_w cgen_jmp_extra_long(struct codegen_context *ctx)
862         cgen_mips_imm(MIPS_LUI, R_AT, 0, 0);
863         cgen_mips_imm(MIPS_BGEZAL, 0, R_ZERO, 1);
864         cgen_mips_imm(MIPS_ORI, R_AT, R_AT, 0);
865         cgen_mips_3reg(OP_SIZE_ADDRESS == OP_SIZE_8 ? MIPS_DADDU : MIPS_ADDU, R_AT, R_AT, R_RA);
866         if (!MIPS_R6) {
867                 cgen_mips_3reg(MIPS_JR, 0, R_AT, 0);
868                 cgen_four(MIPS_NOP);
869         } else {
870                 cgen_mips_imm(MIPS_R6_JIC, R_AT, 0, 0);
871         }
872         return true;
875 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
877         if (MIPS_R6 && length <= JMP_LONG) {
878                 g(cgen_jump_not_last(ctx, 1));
879                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
880                 cgen_four(MIPS_R6_BC);
881                 return true;
882         }
883         if (length == JMP_SHORTEST) {
884                 g(cgen_jump_not_last(ctx, 1));
885                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
886                 cgen_mips_imm(MIPS_BEQ, R_ZERO, R_ZERO, 0);
887                 cgen_four(MIPS_NOP);
888                 return true;
889         }
890         g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length()));
891         g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
892         g(cgen_jmp_extra_long(ctx));
893         return true;
896 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
898         uint32_t mc;
899         uint8_t *arg1 = ctx->code_position;
900         ctx->code_position = arg1 + arg_size(*arg1);
902         if (arg1[0] >= 0x20)
903                 goto invalid;
905         if (MIPS_R6 && (cond == COND_E || cond == COND_NE) && length <= JMP_SHORT) {
906                 mc = cond == COND_E ? MIPS_R6_BEQZC : MIPS_R6_BNEZC;
907                 g(cgen_jump_not_last(ctx, 1));
908                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
909                 cgen_four(mc | ((uint32_t)arg1[0] << 21));
910                 cgen_four(MIPS_NOP);
911                 return true;
912         }
914         if (length > JMP_SHORTEST)
915                 cond ^= 1;
917         switch (cond) {
918                 case COND_E:    mc = MIPS_BEQ; break;
919                 case COND_NE:   mc = MIPS_BNE; break;
920                 case COND_S:
921                 case COND_L:    mc = MIPS_BLTZ; break;
922                 case COND_LE:   mc = MIPS_BLEZ; break;
923                 case COND_G:    mc = MIPS_BGTZ; break;
924                 case COND_NS:
925                 case COND_GE:   mc = MIPS_BGEZ; break;
926                 default:        goto invalid;
927         }
929         if (length == JMP_SHORTEST) {
930                 g(cgen_jump_not_last(ctx, 1));
931                 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
932                 cgen_mips_imm(mc, 0, arg1[0], 0);
933                 cgen_four(MIPS_NOP);
934                 return true;
935         }
936         if (MIPS_R6 && length <= JMP_LONG) {
937                 g(cgen_jump_not_last(ctx, 3));
938                 cgen_mips_imm(mc, 0, arg1[0], 2);
939                 cgen_four(MIPS_NOP);
940                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
941                 cgen_four(MIPS_R6_BC);
942                 return true;
943         }
944         g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
945         cgen_mips_imm(mc, 0, arg1[0], cgen_jmp_extra_long_length());
946         g(add_relocation(ctx, JMP_EXTRA_LONG, 1, NULL));
947         g(cgen_jmp_extra_long(ctx));
948         return true;
950 invalid:
951         internal(file_line, "cgen_jmp_reg: invalid arguments %u, %u, %02x", cond, length, arg1[0]);
952         return false;
955 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
957         uint32_t mc;
958         uint8_t *arg1 = ctx->code_position;
959         uint8_t *arg2 = arg1 + arg_size(*arg1);
960         ctx->code_position = arg2 + arg_size(*arg2);
961         if (arg1[0] >= 0x20 || arg2[0] >= 0x20 || (cond != COND_E && cond != COND_NE))
962                 goto invalid;
964         if (length > JMP_SHORTEST)
965                 cond ^= 1;
967         mc = cond == COND_E ? MIPS_BEQ : MIPS_BNE;
969         if (length == JMP_SHORTEST) {
970                 g(cgen_jump_not_last(ctx, 1));
971                 g(add_relocation(ctx, JMP_SHORTEST, 2, NULL));
972                 cgen_mips_imm(mc, arg1[0], arg2[0], 0);
973                 cgen_four(MIPS_NOP);
974                 return true;
975         }
976         if (MIPS_R6 && length <= JMP_LONG) {
977                 g(cgen_jump_not_last(ctx, 3));
978                 cgen_mips_imm(mc, arg1[0], arg2[0], 2);
979                 cgen_four(MIPS_NOP);
980                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
981                 cgen_four(MIPS_R6_BC);
982                 return true;
983         }
984         g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
985         cgen_mips_imm(mc, arg1[0], arg2[0], cgen_jmp_extra_long_length());
986         g(add_relocation(ctx, JMP_EXTRA_LONG, 2, NULL));
987         g(cgen_jmp_extra_long(ctx));
988         return true;
990 invalid:
991         internal(file_line, "cgen_jmp_2regs: invalid arguments %u, %u, %02x, %02x", cond, length, arg1[0], arg2[0]);
992         return false;
995 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned aux, unsigned length)
997         uint32_t mc;
998         bool t = true;
999         if (fp_condition_negated(aux))
1000                 t = !t;
1001         if (length > JMP_SHORTEST)
1002                 t = !t;
1003         if (MIPS_R6) {
1004                 mc = t ? MIPS_R6_BC1NEZ : MIPS_R6_BC1EQZ;
1005                 if (length == JMP_SHORTEST) {
1006                         g(cgen_jump_not_last(ctx, 1));
1007                         g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1008                         cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 0);
1009                         cgen_four(MIPS_NOP);
1010                         return true;
1011                 }
1012                 if (length <= JMP_LONG) {
1013                         g(cgen_jump_not_last(ctx, 3));
1014                         cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, 2);
1015                         cgen_four(MIPS_NOP);
1016                         g(add_relocation(ctx, JMP_LONG, 0, NULL));
1017                         cgen_four(MIPS_R6_BC);
1018                         return true;
1019                 }
1020                 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1021                 cgen_mips_imm(mc, FR_CMP_RESULT & 31, 0, cgen_jmp_extra_long_length());
1022                 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1023                 g(cgen_jmp_extra_long(ctx));
1024                 return true;
1025         } else {
1026                 mc = t ? MIPS_BC1T : MIPS_BC1F;
1027                 if (length == JMP_SHORTEST) {
1028                         g(cgen_jump_not_last(ctx, 1));
1029                         g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1030                         cgen_mips_imm(mc, 0, 0, 0);
1031                         cgen_four(MIPS_NOP);
1032                         return true;
1033                 }
1034                 g(cgen_jump_not_last(ctx, cgen_jmp_extra_long_length() + 1));
1035                 cgen_mips_imm(mc, 0, 0, cgen_jmp_extra_long_length());
1036                 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
1037                 g(cgen_jmp_extra_long(ctx));
1038                 return true;
1039         }
1042 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, unsigned reg, bool call)
1044         g(cgen_jump_not_last(ctx, 1));
1045         if (!call) {
1046                 if (!MIPS_R6) {
1047                         cgen_mips_3reg(MIPS_JR, 0, reg, 0);
1048                         cgen_four(MIPS_NOP);
1049                 } else {
1050                         cgen_mips_imm(MIPS_R6_JIC, reg, 0, 0);
1051                 }
1052         } else {
1053                 if (!MIPS_R6) {
1054                         cgen_mips_3reg(MIPS_JALR, R_RA, reg, 0);
1055                         cgen_four(MIPS_NOP);
1056                 } else {
1057                         cgen_mips_imm(MIPS_R6_JIALC, reg, 0, 0);
1058                 }
1059         }
1060         return true;
1064 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1066         uint32_t mc;
1067         int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1068         switch (reloc->length) {
1069                 case JMP_SHORTEST:
1070                         offs /= 4;
1071                         offs--;
1072                         if (offs != (int16_t)offs)
1073                                 return false;
1074                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1075                         mc &= ~0xFFFFU;
1076                         mc |= offs & 0xFFFFU;
1077                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1078                         return true;
1079                 case JMP_SHORT:
1080                         offs /= 4;
1081                         offs--;
1082                         if (offs < -0x00100000 || offs >= 0x00100000)
1083                                 return false;
1084                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1085                         mc &= ~0x001FFFFFU;
1086                         mc |= offs & 0x001FFFFFU;
1087                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1088                         return true;
1089                 case JMP_LONG:
1090                         offs /= 4;
1091                         offs--;
1092                         if (offs < -0x02000000 || offs >= 0x02000000)
1093                                 return false;
1094                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1095                         mc &= ~0x03FFFFFFU;
1096                         mc |= offs & 0x03FFFFFFU;
1097                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1098                         return true;
1099                 case JMP_EXTRA_LONG:
1100                         offs -= 12;
1101                         if (offs != (int32_t)offs)
1102                                 return false;
1103                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1104                         mc &= ~0xFFFFU;
1105                         mc |= ((uint64_t)offs >> 16) & 0xFFFFU;
1106                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1107                         memcpy(&mc, ctx->mcode + reloc->position + 8, 4);
1108                         mc &= ~0xFFFFU;
1109                         mc |= offs & 0xFFFFU;
1110                         memcpy(ctx->mcode + reloc->position + 8, &mc, 4);
1111                         return true;
1112                 default:
1113                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1114         }
1115         return false;
1119 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1121         if (unlikely(insn_writes_flags(insn))) {
1122                 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
1123                         goto invalid_insn;
1124         }
1125         switch (insn_opcode(insn)) {
1126                 case INSN_ENTRY:
1127                         g(cgen_entry(ctx));
1128                         return true;
1129                 case INSN_LABEL:
1130                         g(cgen_label(ctx));
1131                         return true;
1132                 case INSN_RET:
1133                         g(cgen_jmp_call_indirect(ctx, R_RA, false));
1134                         if (MIPS_R6)
1135                                 cgen_four(MIPS_NOP);
1136                         return true;
1137                 case INSN_CALL_INDIRECT:
1138                         g(cgen_jmp_call_indirect(ctx, cget_one(ctx), true));
1139                         return true;
1140                 case INSN_MOV:
1141                         g(cgen_mov(ctx, insn_op_size(insn), false));
1142                         return true;
1143                 case INSN_MOVSX:
1144                         g(cgen_mov(ctx, insn_op_size(insn), true));
1145                         return true;
1146                 case INSN_MOV_LR:
1147                         g(cgen_mov_lr(ctx, insn_op_size(insn), insn_aux(insn) != 0));
1148                         return true;
1149                 case INSN_CMP_DEST_REG:
1150                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1151                                 goto invalid_insn;
1152                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
1153                         return true;
1154                 case INSN_ALU:
1155                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1156                                 goto invalid_insn;
1157                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), false));
1158                         return true;
1159                 case INSN_ALU_TRAP:
1160                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1161                                 goto invalid_insn;
1162                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), true));
1163                         return true;
1164                 case INSN_ALU1:
1165                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1166                                 goto invalid_insn;
1167                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), false));
1168                         return true;
1169                 case INSN_ALU1_TRAP:
1170                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1171                                 goto invalid_insn;
1172                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), true));
1173                         return true;
1174                 case INSN_ROT:
1175                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1176                                 goto invalid_insn;
1177                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
1178                         return true;
1179                 case INSN_MUL_L:
1180                         if (unlikely(insn_op_size(insn) <= OP_SIZE_2) || unlikely(insn_op_size(insn) > OP_SIZE_NATIVE))
1181                                 goto invalid_insn;
1182                         g(cgen_mul_l(ctx, insn_op_size(insn)));
1183                         return true;
1184                 case INSN_FP_CMP_COND:
1185                         g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
1186                         return true;
1187                 case INSN_FP_TEST_REG:
1188                         g(cgen_fp_test_reg(ctx, insn_aux(insn)));
1189                         return true;
1190                 case INSN_FP_ALU:
1191                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1192                         return true;
1193                 case INSN_FP_ALU1:
1194                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1195                         return true;
1196                 case INSN_FP_TO_INT32:
1197                 case INSN_FP_TO_INT64:
1198                         g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1199                         return true;
1200                 case INSN_FP_FROM_INT32:
1201                 case INSN_FP_FROM_INT64:
1202                         g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1203                         return true;
1204                 case INSN_JMP:
1205                         g(cgen_jmp(ctx, insn_jump_size(insn)));
1206                         return true;
1207                 case INSN_JMP_REG:
1208                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
1209                         return true;
1210                 case INSN_JMP_2REGS:
1211                         g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
1212                         return true;
1213                 case INSN_JMP_FP_TEST:
1214                         g(cgen_jmp_fp_test(ctx, insn_aux(insn), insn_jump_size(insn)));
1215                         return true;
1216                 case INSN_JMP_INDIRECT:
1217                         g(cgen_jmp_call_indirect(ctx, cget_one(ctx), false));
1218                         return true;
1219                 default:
1220                 invalid_insn:
1221                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
1222                         return false;
1223         }