Ajla 0.1.5
[ajla.git] / c2-loong.inc
blob91960702d2fd18a9fdfff68a71cec40258f13c20
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 LOONG_CLO_W             0x00001000U
20 #define LOONG_CLZ_W             0x00001400U
21 #define LOONG_CTO_W             0x00001800U
22 #define LOONG_CTZ_W             0x00001c00U
23 #define LOONG_CLO_D             0x00002000U
24 #define LOONG_CLZ_D             0x00002400U
25 #define LOONG_CTO_D             0x00002800U
26 #define LOONG_CTZ_D             0x00002c00U
27 #define LOONG_REVB_2H           0x00003000U
28 #define LOONG_REVB_4H           0x00003400U
29 #define LOONG_REVB_2W           0x00003800U
30 #define LOONG_REVB_D            0x00003c00U
31 #define LOONG_REVH_2W           0x00004000U
32 #define LOONG_REVH_D            0x00004400U
33 #define LOONG_BITREV_W          0x00005000U
34 #define LOONG_BITREV_D          0x00005400U
35 #define LOONG_EXT_W_H           0x00005800U
36 #define LOONG_EXT_W_B           0x00005c00U
37 #define LOONG_ADD_W             0x00100000U
38 #define LOONG_ADD_D             0x00108000U
39 #define LOONG_SUB_W             0x00110000U
40 #define LOONG_SUB_D             0x00118000U
41 #define LOONG_SLT               0x00120000U
42 #define LOONG_SLTU              0x00128000U
43 #define LOONG_NOR               0x00140000U
44 #define LOONG_AND               0x00148000U
45 #define LOONG_OR                0x00150000U
46 #define LOONG_XOR               0x00158000U
47 #define LOONG_ORN               0x00160000U
48 #define LOONG_ANDN              0x00168000U
49 #define LOONG_SLL_W             0x00170000U
50 #define LOONG_SRL_W             0x00178000U
51 #define LOONG_SRA_W             0x00180000U
52 #define LOONG_SLL_D             0x00188000U
53 #define LOONG_SRL_D             0x00190000U
54 #define LOONG_SRA_D             0x00198000U
55 #define LOONG_ROTR_W            0x001b0000U
56 #define LOONG_ROTR_D            0x001b8000U
57 #define LOONG_MUL_W             0x001c0000U
58 #define LOONG_MULH_W            0x001c8000U
59 #define LOONG_MULH_WU           0x001d0000U
60 #define LOONG_MUL_D             0x001d8000U
61 #define LOONG_MULH_D            0x001e0000U
62 #define LOONG_MULH_DU           0x001e8000U
63 #define LOONG_DIV_W             0x00200000U
64 #define LOONG_MOD_W             0x00208000U
65 #define LOONG_DIV_WU            0x00210000U
66 #define LOONG_MOD_WU            0x00218000U
67 #define LOONG_DIV_D             0x00220000U
68 #define LOONG_MOD_D             0x00228000U
69 #define LOONG_DIV_DU            0x00230000U
70 #define LOONG_MOD_DU            0x00238000U
71 #define LOONG_SLLI_W            0x00408000U
72 #define LOONG_SLLI_D            0x00410000U
73 #define LOONG_SRLI_W            0x00448000U
74 #define LOONG_SRLI_D            0x00450000U
75 #define LOONG_SRAI_W            0x00488000U
76 #define LOONG_SRAI_D            0x00490000U
77 #define LOONG_ROTRI_W           0x004c8000U
78 #define LOONG_ROTRI_D           0x004d0000U
79 #define LOONG_BSTRINS_W         0x00600000U
80 #define LOONG_BSTRPICK_W        0x00608000U
81 #define LOONG_BSTRINS_D         0x00800000U
82 #define LOONG_BSTRPICK_D        0x00c00000U
83 #define LOONG_FADD_S            0x01008000U
84 #define LOONG_FADD_D            0x01010000U
85 #define LOONG_FSUB_S            0x01028000U
86 #define LOONG_FSUB_D            0x01030000U
87 #define LOONG_FMUL_S            0x01048000U
88 #define LOONG_FMUL_D            0x01050000U
89 #define LOONG_FDIV_S            0x01068000U
90 #define LOONG_FDIV_D            0x01070000U
91 #define LOONG_FNEG_S            0x01141400U
92 #define LOONG_FNEG_D            0x01141800U
93 #define LOONG_FSQRT_S           0x01144400U
94 #define LOONG_FSQRT_D           0x01144800U
95 #define LOONG_MOVFR2GR_S        0x0114b400U
96 #define LOONG_MOVFR2GR_D        0x0114b800U
97 #define LOONG_MOVCF2GR          0x0114dc00U
98 #define LOONG_FTINTRZ_W_S       0x011a8400U
99 #define LOONG_FTINTRZ_W_D       0x011a8800U
100 #define LOONG_FTINTRZ_L_S       0x011aa400U
101 #define LOONG_FTINTRZ_L_D       0x011aa800U
102 #define LOONG_FFINT_S_W         0x011d1000U
103 #define LOONG_FFINT_S_L         0x011d1800U
104 #define LOONG_FFINT_D_W         0x011d2000U
105 #define LOONG_FFINT_D_L         0x011d2800U
106 #define LOONG_FRINT_S           0x011e4400U
107 #define LOONG_FRINT_D           0x011e4800U
108 #define LOONG_SLTI              0x02000000U
109 #define LOONG_SLTUI             0x02400000U
110 #define LOONG_ADDI_W            0x02800000U
111 #define LOONG_ADDI_D            0x02c00000U
112 #define LOONG_LU52I_D           0x03000000U
113 #define LOONG_ANDI              0x03400000U
114 #define LOONG_ORI               0x03800000U
115 #define LOONG_XORI              0x03c00000U
116 #define LOONG_FCMP_S            0x0c100000U
117 #define LOONG_FCMP_D            0x0c200000U
118 #define  LOONG_FCMP_SIG                 0x00008000U
119 #define  LOONG_FCMP_AF                  0x00000000U
120 #define  LOONG_FCMP_LT                  0x00010000U
121 #define  LOONG_FCMP_EQ                  0x00020000U
122 #define  LOONG_FCMP_LE                  0x00030000U
123 #define  LOONG_FCMP_UN                  0x00040000U
124 #define  LOONG_FCMP_ULT                 0x00050000U
125 #define  LOONG_FCMP_UEQ                 0x00060000U
126 #define  LOONG_FCMP_ULE                 0x00070000U
127 #define  LOONG_FCMP_NE                  0x00080000U
128 #define  LOONG_FCMP_OR                  0x000a0000U
129 #define  LOONG_FCMP_UNE                 0x000c0000U
130 #define LOONG_LU12I_W           0x14000000U
131 #define LOONG_LU32I_D           0x16000000U
132 #define LOONG_LDPTR_W           0x24000000U
133 #define LOONG_LDPTR_D           0x26000000U
134 #define LOONG_STPTR_W           0x25000000U
135 #define LOONG_STPTR_D           0x27000000U
136 #define LOONG_LD_B              0x28000000U
137 #define LOONG_LD_H              0x28400000U
138 #define LOONG_LD_W              0x28800000U
139 #define LOONG_LD_D              0x28c00000U
140 #define LOONG_ST_B              0x29000000U
141 #define LOONG_ST_H              0x29400000U
142 #define LOONG_ST_W              0x29800000U
143 #define LOONG_ST_D              0x29c00000U
144 #define LOONG_LD_BU             0x2a000000U
145 #define LOONG_LD_HU             0x2a400000U
146 #define LOONG_LD_WU             0x2a800000U
147 #define LOONG_FLD_S             0x2b000000U
148 #define LOONG_FST_S             0x2b400000U
149 #define LOONG_FLD_D             0x2b800000U
150 #define LOONG_FST_D             0x2bc00000U
151 #define LOONG_LDX_B             0x38000000U
152 #define LOONG_LDX_H             0x38040000U
153 #define LOONG_LDX_W             0x38080000U
154 #define LOONG_LDX_D             0x380c0000U
155 #define LOONG_STX_B             0x38100000U
156 #define LOONG_STX_H             0x38140000U
157 #define LOONG_STX_W             0x38180000U
158 #define LOONG_STX_D             0x381c0000U
159 #define LOONG_LDX_BU            0x38200000U
160 #define LOONG_LDX_HU            0x38240000U
161 #define LOONG_LDX_WU            0x38280000U
162 #define LOONG_FLDX_S            0x38300000U
163 #define LOONG_FLDX_D            0x38340000U
164 #define LOONG_FSTX_S            0x38380000U
165 #define LOONG_FSTX_D            0x383c0000U
166 #define LOONG_BEQZ              0x40000000U
167 #define LOONG_BNEZ              0x44000000U
168 #define LOONG_BCEQZ             0x48000000U
169 #define LOONG_BCNEZ             0x48000100U
170 #define LOONG_JIRL              0x4c000000U
171 #define LOONG_B                 0x50000000U
172 #define LOONG_BEQ               0x58000000U
173 #define LOONG_BNE               0x5c000000U
174 #define LOONG_BLT               0x60000000U
175 #define LOONG_BGE               0x64000000U
176 #define LOONG_BLTU              0x68000000U
177 #define LOONG_BGEU              0x6c000000U
180 #define cgen_i26(opcode, imm)                   cgen_four((opcode) | ((imm) & 0xffffU) << 10 | ((imm) & 0x3ff0000) >> 16)
181 #define cgen_1ri20(opcode, rd, imm)             cgen_four((opcode) | (rd) | ((imm) & 0xFFFFFU) << 5)
182 #define cgen_1ri21(opcode, rj, imm)             cgen_four((opcode) | (rj) << 5 | ((imm) & 0xFFFFU) << 5 | ((imm) & 0x1f0000) >> 16)
183 #define cgen_2r(opcode, rd, rj)                 cgen_four((opcode) | (rd) | (rj) << 5)
184 #define cgen_2ri8(opcode, rd, rj, imm)          cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xffU) << 10)
185 #define cgen_2ri12(opcode, rd, rj, imm)         cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xfffU) << 10)
186 #define cgen_2ri14(opcode, rd, rj, imm)         cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0x3fffU) << 10)
187 #define cgen_2ri16(opcode, rd, rj, imm)         cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xffffU) << 10)
188 #define cgen_2r2i(opcode, rd, rj, imm_m, imm_l) cgen_four((opcode) | (rd) | (rj) << 5 | (imm_m) << 16 | (imm_l) << 10)
189 #define cgen_3r(opcode, rd, rj, rk)             cgen_four((opcode) | (rd) | (rj) << 5 | ((rk) << 10))
191 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, bool call)
193         uint8_t reg = cget_one(ctx);
194         uint8_t save = call ? R_RA : R_ZERO;
195         cgen_2ri16(LOONG_JIRL, save, reg, 0);
196         return true;
199 static const uint32_t st[10] =          { LOONG_ST_B, LOONG_ST_H, LOONG_ST_W, LOONG_ST_D, LOONG_STX_B, LOONG_STX_H, LOONG_STX_W, LOONG_STX_D, LOONG_STPTR_W, LOONG_STPTR_D };
200 static const uint32_t ld_signed[10] =   { LOONG_LD_B, LOONG_LD_H, LOONG_LD_W, LOONG_LD_D, LOONG_LDX_B, LOONG_LDX_H, LOONG_LDX_W, LOONG_LDX_D, LOONG_LDPTR_W, LOONG_LDPTR_D };
201 static const uint32_t ld_unsigned[10] = { LOONG_LD_BU, LOONG_LD_HU, LOONG_LD_WU, LOONG_LD_D, LOONG_LDX_BU, LOONG_LDX_HU, LOONG_LDX_WU, LOONG_LDX_D, -1U, LOONG_LDPTR_D };
202 static const uint32_t st_fp[10] =       { -1U, -1U, LOONG_FST_S, LOONG_FST_D, -1U, -1U, LOONG_FSTX_S, LOONG_FSTX_D, -1U, -1U };
203 static const uint32_t ld_fp[10] =       { -1U, -1U, LOONG_FLD_S, LOONG_FLD_D, -1U, -1U, LOONG_FLDX_S, LOONG_FLDX_D, -1U, -1U };
205 static bool cgen_ld_st(struct codegen_context *ctx, const uint32_t table[10], unsigned size, uint8_t reg, uint8_t *address)
207         int64_t imm;
208         if (address[0] == ARG_ADDRESS_1) {
209                 imm = get_imm(&address[2]);
210                 if (!(imm & 3) && imm >= -0x8000 && imm < 0x8000 && (size == OP_SIZE_4 || size == OP_SIZE_8)) {
211                         uint32_t mc = table[8 + size - OP_SIZE_4];
212                         if (mc != -1U) {
213                                 cgen_2ri14(mc, reg, address[1], (uint64_t)imm >> 2);
214                                 return true;
215                         }
216                 }
217                 if (imm >= -0x800 && imm < 0x800) {
218                         cgen_2ri12(table[size], reg, address[1], imm);
219                         return true;
220                 }
221         } else if (address[0] == ARG_ADDRESS_2) {
222                 imm = get_imm(&address[3]);
223                 if (unlikely(imm != 0))
224                         goto invalid;
225                 cgen_3r(table[4 + size], reg, address[1], address[2]);
226                 return true;
227         }
228 invalid:
229         internal(file_line, "cgen_ld_st: invalid arguments %02x, %02x", reg, address[0]);
230         return false;
233 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
235         int64_t imm;
236         uint8_t *arg1 = ctx->code_position;
237         uint8_t *arg2 = arg1 + arg_size(*arg1);
238         ctx->code_position = arg2 + arg_size(*arg2);
239         if (size == OP_SIZE_NATIVE)
240                 sx = false;
241         if (arg1[0] < 0x20) {
242                 if (arg2[0] < 0x20) {
243                         if (sx) {
244                                 switch (size) {
245                                         case OP_SIZE_1:
246                                                 cgen_2r(LOONG_EXT_W_B, arg1[0], arg2[0]);
247                                                 return true;
248                                         case OP_SIZE_2:
249                                                 cgen_2r(LOONG_EXT_W_H, arg1[0], arg2[0]);
250                                                 return true;
251                                         case OP_SIZE_4:
252                                                 cgen_2ri8(LOONG_SLLI_W, arg1[0], arg2[0], 0);
253                                                 return true;
254                                         default:
255                                                 goto invalid;
256                                 }
257                         } else {
258                                 switch (size) {
259                                         case OP_SIZE_1:
260                                                 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x07, 0x00);
261                                                 return true;
262                                         case OP_SIZE_2:
263                                                 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x0f, 0x00);
264                                                 return true;
265                                         case OP_SIZE_4:
266                                                 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x1f, 0x00);
267                                                 return true;
268                                         case OP_SIZE_8:
269                                                 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
270                                                 return true;
271                                         default:
272                                                 goto invalid;
273                                 }
274                         }
275                 }
276                 if (arg2[0] < 0x40) {
277                         switch (size) {
278                                 case OP_SIZE_4:
279                                         cgen_2r(LOONG_MOVFR2GR_S, arg1[0], arg2[0] & 0x1f);
280                                         return true;
281                                 case OP_SIZE_8:
282                                         cgen_2r(LOONG_MOVFR2GR_D, arg1[0], arg2[0] & 0x1f);
283                                         return true;
284                                 default:
285                                         goto invalid;
286                         }
287                 }
288                 if (arg2[0] == ARG_IMM) {
289                         imm = get_imm(&arg2[1]);
290                         if (imm >= 0 && imm < 0x1000) {
291                                 cgen_2ri12(LOONG_ORI, arg1[0], R_ZERO, imm);
292                                 return true;
293                         }
294                         if (imm >= -0x800 && imm < 0x800) {
295                                 cgen_2ri12(LOONG_ADDI_D, arg1[0], R_ZERO, imm);
296                                 return true;
297                         }
298                         if (!(imm & 0xfff) && imm == (int32_t)imm) {
299                                 cgen_1ri20(LOONG_LU12I_W, arg1[0], (uint64_t)imm >> 12);
300                                 return true;
301                         }
302                         if (!(imm & 0x000fffffffffffffLL)) {
303                                 cgen_2ri12(LOONG_LU52I_D, arg1[0], R_ZERO, (uint64_t)imm >> 52);
304                                 return true;
305                         }
306                         goto invalid;
307                 }
308                 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
309                         if (!sx)
310                                 return cgen_ld_st(ctx, ld_unsigned, size, arg1[0], arg2);
311                         else
312                                 return cgen_ld_st(ctx, ld_signed, size, arg1[0], arg2);
313                 }
314                 goto invalid;
315         }
317         if (arg1[0] < 0x40) {
318                 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
319                         return cgen_ld_st(ctx, ld_fp, size, arg1[0] & 0x1f, arg2);
320                 }
321         }
323         if (arg1[0] == ARG_ADDRESS_1 || arg1[0] == ARG_ADDRESS_2) {
324                 if (arg2[0] < 0x20) {
325                         return cgen_ld_st(ctx, st, size, arg2[0], arg1);
326                 }
327                 if (arg2[0] < 0x40) {
328                         return cgen_ld_st(ctx, st_fp, size, arg2[0] & 0x1f, arg1);
329                 }
330                 if (arg2[0] == ARG_IMM) {
331                         imm = get_imm(&arg2[1]);
332                         if (unlikely(imm != 0))
333                                 goto invalid;
334                         return cgen_ld_st(ctx, st, size, R_ZERO, arg1);
335                 }
336         }
338 invalid:
339         internal(file_line, "cgen_mov: invalid arguments %02x, %02x", arg1[0], arg2[0]);
340         return false;
343 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
345         uint32_t mc;
346         bool swap = false;
347         uint8_t z = R_ZERO;
348         uint8_t *arg1 = ctx->code_position;
349         uint8_t *arg2 = arg1 + arg_size(*arg1);
350         uint8_t *arg3 = arg2 + arg_size(*arg2);
351         ctx->code_position = arg3 + arg_size(*arg3);
352         if (arg3[0] == ARG_IMM) {
353                 int64_t imm = get_imm(&arg3[1]);
354                 if (unlikely(imm < -0x800) && unlikely(imm >= 0x800))
355                         internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
356                 switch (aux) {
357                         case COND_B:    mc = LOONG_SLTUI; break;
358                         case COND_L:    mc = LOONG_SLTI; break;
359                         default:        internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
360                 }
361                 cgen_2ri12(mc, arg1[0], arg2[0], imm);
362                 return true;
363         }
364         if (arg2[0] == ARG_IMM) {
365                 int64_t imm = get_imm(&arg2[1]);
366                 if (unlikely(imm != 0))
367                         internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
368                 arg2 = &z;
369         }
370         switch (aux) {
371                 case COND_B:    mc = LOONG_SLTU; break;
372                 case COND_A:    mc = LOONG_SLTU; swap = true; break;
373                 case COND_L:    mc = LOONG_SLT; break;
374                 case COND_G:    mc = LOONG_SLT; swap = true; break;
375                 default:        internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
376         }
377         if (swap) {
378                 uint8_t *argx = arg2;
379                 arg2 = arg3;
380                 arg3 = argx;
381         }
382         cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
383         return true;
386 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
388         uint32_t mc;
389         uint8_t *arg1 = ctx->code_position;
390         uint8_t *arg2 = arg1 + arg_size(*arg1);
391         uint8_t *arg3 = arg2 + arg_size(*arg2);
392         ctx->code_position = arg3 + arg_size(*arg3);
394         if (arg3[0] == ARG_IMM) {
395                 int64_t imm = get_imm(&arg3[1]);
396                 if (alu == ALU_SUB) {
397                         imm = -(uint64_t)imm;
398                         alu = ALU_ADD;
399                 }
400                 if (alu == ALU_ADD) {
401                         if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
402                                 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
403                 } else {
404                         if (unlikely(imm < 0) || unlikely(imm >= 0x1000))
405                                 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
406                 }
407                 switch (alu) {
408                         case ALU_ADD:   mc = size == OP_SIZE_8 ? LOONG_ADDI_D : LOONG_ADDI_W; break;
409                         case ALU_XOR:   mc = LOONG_XORI; break;
410                         case ALU_OR:    mc = LOONG_ORI; break;
411                         case ALU_AND:   mc = LOONG_ANDI; break;
412                         default:        internal(file_line, "cgen_alu: invalid alu %u", alu);
413                 }
414                 cgen_2ri12(mc, arg1[0], arg2[0], imm);
415                 return true;
416         }
418         switch (alu) {
419                 case ALU_ADD:   mc = size == OP_SIZE_8 ? LOONG_ADD_D : LOONG_ADD_W; break;
420                 case ALU_SUB:   mc = size == OP_SIZE_8 ? LOONG_SUB_D : LOONG_SUB_W; break;
421                 case ALU_XOR:   mc = LOONG_XOR; break;
422                 case ALU_OR:    mc = LOONG_OR; break;
423                 case ALU_AND:   mc = LOONG_AND; break;
424                 case ALU_ANDN:  mc = LOONG_ANDN; break;
425                 case ALU_ORN:   mc = LOONG_ORN; break;
426                 case ALU_MUL:   mc = size == OP_SIZE_8 ? LOONG_MUL_D : LOONG_MUL_W; break;
427                 case ALU_SMULH: mc = size == OP_SIZE_8 ? LOONG_MULH_D : LOONG_MULH_W; break;
428                 case ALU_UDIV:  mc = size == OP_SIZE_8 ? LOONG_DIV_DU : LOONG_DIV_WU; break;
429                 case ALU_SDIV:  mc = size == OP_SIZE_8 ? LOONG_DIV_D : LOONG_DIV_W; break;
430                 case ALU_UREM:  mc = size == OP_SIZE_8 ? LOONG_MOD_DU : LOONG_MOD_WU; break;
431                 case ALU_SREM:  mc = size == OP_SIZE_8 ? LOONG_MOD_D : LOONG_MOD_W; break;
432                 default:        internal(file_line, "cgen_alu: invalid alu %u", alu);
433         }
434         cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
435         return true;
438 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
440         uint8_t *arg1 = ctx->code_position;
441         uint8_t *arg2 = arg1 + arg_size(*arg1);
442         ctx->code_position = arg2 + arg_size(*arg2);
443         switch (alu) {
444                 case ALU1_NOT:
445                         cgen_3r(LOONG_NOR, arg1[0], R_ZERO, arg2[0]);
446                         return true;
447                 case ALU1_NEG:
448                         cgen_3r(size == OP_SIZE_4 ? LOONG_SUB_W : LOONG_SUB_D, arg1[0], R_ZERO, arg2[0]);
449                         return true;
450                 case ALU1_INC:
451                         cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], 1);
452                         return true;
453                 case ALU1_DEC:
454                         cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], -1);
455                         return true;
456                 case ALU1_BSWAP:
457                         if (size == OP_SIZE_4) {
458                                 cgen_2r(LOONG_REVB_2H, arg1[0], arg2[0]);
459                                 cgen_2ri8(LOONG_ROTRI_W, arg1[0], arg1[0], 0x10);
460                                 return true;
461                         } else {
462                                 cgen_2r(LOONG_REVB_4H, arg1[0], arg2[0]);
463                                 cgen_2r(LOONG_REVH_D, arg1[0], arg1[0]);
464                                 return true;
465                         }
466                 case ALU1_BSWAP16:
467                         cgen_2r(size == OP_SIZE_4 ? LOONG_REVB_2H : LOONG_REVB_4H, arg1[0], arg2[0]);
468                         return true;
469                 case ALU1_BREV:
470                         cgen_2r(size == OP_SIZE_4 ? LOONG_BITREV_W : LOONG_BITREV_D, arg1[0], arg2[0]);
471                         return true;
472                 case ALU1_BSF:
473                         cgen_2r(size == OP_SIZE_4 ? LOONG_CTZ_W : LOONG_CTZ_D, arg1[0], arg2[0]);
474                         return true;
475                 case ALU1_LZCNT:
476                         cgen_2r(size == OP_SIZE_4 ? LOONG_CLZ_W : LOONG_CLZ_D, arg1[0], arg2[0]);
477                         return true;
478                 default:
479                         internal(file_line, "cgen_alu1: invalid alu %u", alu);
480                         return false;
481         }
484 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
486         uint32_t mc;
487         uint8_t *arg1 = ctx->code_position;
488         uint8_t *arg2 = arg1 + arg_size(*arg1);
489         uint8_t *arg3 = arg2 + arg_size(*arg2);
490         ctx->code_position = arg3 + arg_size(*arg3);
491         if (arg3[0] == ARG_IMM) {
492                 int64_t imm = get_imm(&arg3[1]);
493                 if (alu == ROT_ROL)
494                         imm = -(uint64_t)imm;
495                 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
496                 switch (alu) {
497                         case ROT_ROL:   mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
498                         case ROT_ROR:   mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
499                         case ROT_SHL:   mc = size == OP_SIZE_4 ? LOONG_SLLI_W : LOONG_SLLI_D; break;
500                         case ROT_SHR:   mc = size == OP_SIZE_4 ? LOONG_SRLI_W : LOONG_SRLI_D; break;
501                         case ROT_SAR:   mc = size == OP_SIZE_4 ? LOONG_SRAI_W : LOONG_SRAI_D; break;
502                         default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
503                 }
504                 cgen_2ri8(mc, arg1[0], arg2[0], imm);
505                 return true;
506         }
507         switch (alu) {
508                 case ROT_ROR:   mc = size == OP_SIZE_4 ? LOONG_ROTR_W : LOONG_ROTR_D; break;
509                 case ROT_SHL:   mc = size == OP_SIZE_4 ? LOONG_SLL_W : LOONG_SLL_D; break;
510                 case ROT_SHR:   mc = size == OP_SIZE_4 ? LOONG_SRL_W : LOONG_SRL_D; break;
511                 case ROT_SAR:   mc = size == OP_SIZE_4 ? LOONG_SRA_W : LOONG_SRA_D; break;
512                 default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
513         }
514         cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
515         return true;
518 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
520         int64_t imm;
521         uint8_t *arg1 = ctx->code_position;
522         uint8_t *arg2 = arg1 + arg_size(*arg1);
523         uint8_t *arg3 = arg2 + arg_size(*arg2);
524         ctx->code_position = arg3 + arg_size(*arg3);
525         if (unlikely(arg3[0] != ARG_IMM))
526                 goto invalid;
527         imm = get_imm(&arg3[1]) & 0x3f;
528         switch (alu) {
529                 case BTX_BTR:
530                         if (unlikely(arg1[0] != arg2[0]))
531                                 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
532                         cgen_2r2i(LOONG_BSTRINS_D, arg1[0], R_ZERO, imm, imm);
533                         return true;
534                 case BTX_BTEXT:
535                         cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], imm, imm);
536                         return true;
537         }
539 invalid:
540         internal(file_line, "cgen_btx: bad arguments: %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
541         return false;
544 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
546         uint64_t imm = 0;
547         uint8_t *arg1 = ctx->code_position;
548         uint8_t *arg2 = arg1 + arg_size(*arg1);
549         uint8_t *arg3 = arg2 + arg_size(*arg2);
550         ctx->code_position = arg3 + arg_size(*arg3);
551         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] != ARG_IMM))
552                 goto invalid;
554         imm = get_imm(&arg3[1]);
556         switch (aux) {
557                 case MOV_MASK_32_64:
558                         if (unlikely(arg1[0] != arg2[0]))
559                                 goto invalid;
560                         cgen_1ri20(LOONG_LU32I_D, arg1[0], imm);
561                         return true;
562                 case MOV_MASK_52_64:
563                         cgen_2ri12(LOONG_LU52I_D, arg1[0], arg2[0], imm);
564                         return true;
565                 default:        goto invalid;
566         }
568 invalid:
569         internal(file_line, "cgen_mov_mask: bad arguments: %02x, %02x, %u, %"PRIxMAX"", arg1[0], arg2[0], aux, (uintmax_t)imm);
570         return false;
573 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
575         uint32_t mc;
576         bool swap;
577         uint8_t *arg1 = ctx->code_position;
578         uint8_t *arg2 = arg1 + arg_size(*arg1);
579         ctx->code_position = arg2 + arg_size(*arg2);
581         mc = op_size == OP_SIZE_4 ? LOONG_FCMP_S : LOONG_FCMP_D;
583         switch (aux) {
584                 case FP_COND_P:         mc |= LOONG_FCMP_UN; swap = false; break;
585                 case FP_COND_NP:        mc |= LOONG_FCMP_OR; swap = false; break;
586                 case FP_COND_E:         mc |= LOONG_FCMP_EQ; swap = false; break;
587                 case FP_COND_NE:        mc |= LOONG_FCMP_NE; swap = false; break;
588                 case FP_COND_A:         mc |= LOONG_FCMP_LT; swap = true; break;
589                 case FP_COND_BE:        mc |= LOONG_FCMP_LE; swap = false; break;
590                 case FP_COND_B:         mc |= LOONG_FCMP_LT; swap = false; break;
591                 case FP_COND_AE:        mc |= LOONG_FCMP_LE; swap = true; break;
592                 default:                internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
593                                         return false;
594         }
596         if (swap) {
597                 uint8_t *argx = arg1;
598                 arg1 = arg2;
599                 arg2 = argx;
600         }
602         cgen_3r(mc, 0, arg1[0] & 0x1f, arg2[0] & 0x1f);
603         return true;
606 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx)
608         unsigned reg = cget_one(ctx);
609         cgen_2r(LOONG_MOVCF2GR, reg, 0);
610         return true;
613 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
615         uint32_t mc;
616         uint8_t *arg1 = ctx->code_position;
617         uint8_t *arg2 = arg1 + arg_size(*arg1);
618         uint8_t *arg3 = arg2 + arg_size(*arg2);
619         ctx->code_position = arg3 + arg_size(*arg3);
620         switch (aux) {
621                 case FP_ALU_ADD:        mc = op_size == OP_SIZE_4 ? LOONG_FADD_S : LOONG_FADD_D; break;
622                 case FP_ALU_SUB:        mc = op_size == OP_SIZE_4 ? LOONG_FSUB_S : LOONG_FSUB_D; break;
623                 case FP_ALU_MUL:        mc = op_size == OP_SIZE_4 ? LOONG_FMUL_S : LOONG_FMUL_D; break;
624                 case FP_ALU_DIV:        mc = op_size == OP_SIZE_4 ? LOONG_FDIV_S : LOONG_FDIV_D; break;
625                 default:                internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
626         }
627         cgen_3r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f, arg3[0] & 0x1f);
628         return true;
631 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
633         uint32_t mc;
634         uint8_t *arg1 = ctx->code_position;
635         uint8_t *arg2 = arg1 + arg_size(*arg1);
636         ctx->code_position = arg2 + arg_size(*arg2);
637         switch (aux) {
638                 case FP_ALU1_NEG:       mc = op_size == OP_SIZE_4 ? LOONG_FNEG_S : LOONG_FNEG_D; break;
639                 case FP_ALU1_SQRT:      mc = op_size == OP_SIZE_4 ? LOONG_FSQRT_S : LOONG_FSQRT_D; break;
640                 case FP_ALU1_ROUND:     mc = op_size == OP_SIZE_4 ? LOONG_FRINT_S : LOONG_FRINT_D; break;
641                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
642         }
643         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
644         return true;
647 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
649         uint32_t mc;
650         uint8_t *arg1 = ctx->code_position;
651         uint8_t *arg2 = arg1 + arg_size(*arg1);
652         ctx->code_position = arg2 + arg_size(*arg2);
654         if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
655                 internal(file_line, "cgen_fp_to_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
657         if (int_op_size == OP_SIZE_4) {
658                 if (fp_op_size == OP_SIZE_4)
659                         mc = LOONG_FTINTRZ_W_S;
660                 else
661                         mc = LOONG_FTINTRZ_W_D;
662         } else {
663                 if (fp_op_size == OP_SIZE_4)
664                         mc = LOONG_FTINTRZ_L_S;
665                 else
666                         mc = LOONG_FTINTRZ_L_D;
667         }
668         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
669         return true;
672 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
674         uint32_t mc;
675         uint8_t *arg1 = ctx->code_position;
676         uint8_t *arg2 = arg1 + arg_size(*arg1);
677         ctx->code_position = arg2 + arg_size(*arg2);
679         if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
680                 internal(file_line, "cgen_fp_from_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
682         if (int_op_size == OP_SIZE_4) {
683                 if (fp_op_size == OP_SIZE_4)
684                         mc = LOONG_FFINT_S_W;
685                 else
686                         mc = LOONG_FFINT_D_W;
687         } else {
688                 if (fp_op_size == OP_SIZE_4)
689                         mc = LOONG_FFINT_S_L;
690                 else
691                         mc = LOONG_FFINT_D_L;
692         }
693         cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
694         return true;
697 static bool attr_w cgen_jmp(struct codegen_context *ctx)
699         g(add_relocation(ctx, JMP_LONG, 0, NULL));
700         cgen_i26(LOONG_B, 0);
701         return true;
704 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
706         uint32_t mc;
707         bool swap;
709         if (reg1 >= 0x20 || reg2 >= 0x20)
710                 goto invalid;
712         if (length > JMP_SHORTEST)
713                 cond ^= 1;
715         swap = false;
716         switch (cond) {
717                 case COND_B:    mc = LOONG_BLTU; break;
718                 case COND_AE:   mc = LOONG_BGEU; break;
719                 case COND_E:    mc = LOONG_BEQ; break;
720                 case COND_NE:   mc = LOONG_BNE; break;
721                 case COND_BE:   mc = LOONG_BGEU; swap = true; break;
722                 case COND_A:    mc = LOONG_BLTU; swap = true; break;
723                 case COND_L:    mc = LOONG_BLT; break;
724                 case COND_GE:   mc = LOONG_BGE; break;
725                 case COND_LE:   mc = LOONG_BGE; swap = true; break;
726                 case COND_G:    mc = LOONG_BLT; swap = true; break;
727                 default:        goto invalid;
728         }
731         if (swap) {
732                 unsigned regx = reg1;
733                 reg1 = reg2;
734                 reg2 = regx;
735         }
737         if (length == JMP_SHORTEST) {
738                 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
739                 cgen_2ri16(mc, reg2, reg1, 0);
740                 return true;
741         } else {
742                 cgen_2ri16(mc, reg2, reg1, 2);
743                 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
744                 cgen_i26(LOONG_B, 0);
745                 return true;
746         }
748 invalid:
749         internal(file_line, "cgen_jmp_12regs: invalid arguments %02x, %02x", reg1, reg2);
750         return false;
753 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
755         uint32_t mc;
756         uint8_t *arg1 = ctx->code_position;
757         ctx->code_position = arg1 + arg_size(*arg1);
758         if (arg1[0] >= 0x20)
759                 goto invalid;
761         switch (cond) {
762                 case COND_S:
763                 case COND_L:
764                         g(cgen_jmp_12regs(ctx, COND_L, length, arg1[0], R_ZERO, 1));
765                         return true;
766                 case COND_NS:
767                 case COND_GE:
768                         g(cgen_jmp_12regs(ctx, COND_GE, length, arg1[0], R_ZERO, 1));
769                         return true;
770                 case COND_LE:
771                 case COND_G:
772                         g(cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1));
773                         return true;
774         }
776         if (length > JMP_SHORT)
777                 cond ^= 1;
779         switch (cond) {
780                 case COND_E:    mc = LOONG_BEQZ; break;
781                 case COND_NE:   mc = LOONG_BNEZ; break;
782                 default:        goto invalid;
783         }
785         if (length <= JMP_SHORT) {
786                 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
787                 cgen_1ri21(mc, arg1[0], 0);
788                 return true;
789         } else {
790                 cgen_1ri21(mc, arg1[0], 2);
791                 g(add_relocation(ctx, JMP_LONG, 1, NULL));
792                 cgen_i26(LOONG_B, 0);
793                 return true;
794         }
796 invalid:
797         internal(file_line, "cgen_jmp_reg: invalid argument %02x, %u", arg1[0], cond);
798         return false;
801 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
803         uint8_t *arg1 = ctx->code_position;
804         uint8_t *arg2 = arg1 + arg_size(*arg1);
805         ctx->code_position = arg2 + arg_size(*arg2);
806         g(cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2));
807         return true;
810 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned length)
812         if (length <= JMP_SHORT) {
813                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
814                 cgen_1ri21(LOONG_BCNEZ, 0, 0);
815                 return true;
816         } else {
817                 cgen_1ri21(LOONG_BCEQZ, 0, 2);
818                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
819                 cgen_i26(LOONG_B, 0);
820                 return true;
821         }
824 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
826         uint32_t mc;
827         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
828         switch (reloc->length) {
829                 case JMP_SHORTEST:
830                         if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
831                                 return false;
832                         memcpy(&mc, ctx->mcode + reloc->position, 4);
833                         mc &= ~(0xffffU << 10);
834                         mc |= (offs & 0xffffU) << 10;
835                         memcpy(ctx->mcode + reloc->position, &mc, 4);
836                         return true;
837                 case JMP_SHORT:
838                         if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
839                                 return false;
840                         memcpy(&mc, ctx->mcode + reloc->position, 4);
841                         mc &= ~((0xffffU << 10) | 0x1fU);
842                         mc |= ((offs & 0xffffU) << 10) | ((offs & 0x1f0000U) >> 16);
843                         memcpy(ctx->mcode + reloc->position, &mc, 4);
844                         return true;
845                 case JMP_LONG:
846                         if (unlikely(offs < -0x2000000) || unlikely(offs >= 0x2000000))
847                                 return false;
848                         memcpy(&mc, ctx->mcode + reloc->position, 4);
849                         mc &= ~((0xffffU << 10) | 0x3ffU);
850                         mc |= ((offs & 0xffffU) << 10) | ((offs & 0x3ff0000U) >> 16);
851                         memcpy(ctx->mcode + reloc->position, &mc, 4);
852                         return true;
853                 default:
854                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
855         }
856         return false;
859 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
861         if (unlikely(insn_writes_flags(insn))) {
862                 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
863                         goto invalid_insn;
864         }
865         /*debug("insn: %08x", (unsigned)insn);*/
866         switch (insn_opcode(insn)) {
867                 case INSN_ENTRY:
868                         g(cgen_entry(ctx));
869                         return true;
870                 case INSN_LABEL:
871                         g(cgen_label(ctx));
872                         return true;
873                 case INSN_RET:
874                         cgen_2ri16(LOONG_JIRL, R_ZERO, R_RA, 0);
875                         return true;
876                 case INSN_CALL_INDIRECT:
877                         g(cgen_jmp_call_indirect(ctx, true));
878                         return true;
879                 case INSN_MOV:
880                         g(cgen_mov(ctx, insn_op_size(insn), false));
881                         return true;
882                 case INSN_MOVSX:
883                         g(cgen_mov(ctx, insn_op_size(insn), true));
884                         return true;
885                 case INSN_CMP_DEST_REG:
886                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
887                                 goto invalid_insn;
888                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
889                         return true;
890                 case INSN_ALU:
891                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
892                                 goto invalid_insn;
893                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
894                         return true;
895                 case INSN_ALU1:
896                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
897                                 goto invalid_insn;
898                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
899                         return true;
900                 case INSN_ROT:
901                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
902                                 goto invalid_insn;
903                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
904                         return true;
905                 case INSN_BTX:
906                         g(cgen_btx(ctx, insn_aux(insn)));
907                         return true;
908                 case INSN_MOV_MASK:
909                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
910                                 goto invalid_insn;
911                         g(cgen_mov_mask(ctx, insn_aux(insn)));
912                         return true;
913                 case INSN_FP_CMP_COND:
914                         g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
915                         return true;
916                 case INSN_FP_TEST_REG:
917                         g(cgen_fp_test_reg(ctx));
918                         return true;
919                 case INSN_FP_ALU:
920                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
921                         return true;
922                 case INSN_FP_ALU1:
923                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
924                         return true;
925                 case INSN_FP_TO_INT32:
926                 case INSN_FP_TO_INT64:
927                         g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
928                         return true;
929                 case INSN_FP_FROM_INT32:
930                 case INSN_FP_FROM_INT64:
931                         g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
932                         return true;
933                 case INSN_JMP:
934                         g(cgen_jmp(ctx));
935                         return true;
936                 case INSN_JMP_REG:
937                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
938                                 goto invalid_insn;
939                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
940                         return true;
941                 case INSN_JMP_2REGS:
942                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
943                                 goto invalid_insn;
944                         g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
945                         return true;
946                 case INSN_JMP_FP_TEST:
947                         g(cgen_jmp_fp_test(ctx, insn_jump_size(insn)));
948                         return true;
949                 case INSN_JMP_INDIRECT:
950                         g(cgen_jmp_call_indirect(ctx, false));
951                         return true;
952                 default:
953                 invalid_insn:
954                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
955                         return false;
956         }