2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #define 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);
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)
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];
213 cgen_2ri14(mc, reg, address[1], (uint64_t)imm >> 2);
217 if (imm >= -0x800 && imm < 0x800) {
218 cgen_2ri12(table[size], reg, address[1], imm);
221 } else if (address[0] == ARG_ADDRESS_2) {
222 imm = get_imm(&address[3]);
223 if (unlikely(imm != 0))
225 cgen_3r(table[4 + size], reg, address[1], address[2]);
229 internal(file_line, "cgen_ld_st: invalid arguments %02x, %02x", reg, address[0]);
233 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
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)
241 if (arg1[0] < 0x20) {
242 if (arg2[0] < 0x20) {
246 cgen_2r(LOONG_EXT_W_B, arg1[0], arg2[0]);
249 cgen_2r(LOONG_EXT_W_H, arg1[0], arg2[0]);
252 cgen_2ri8(LOONG_SLLI_W, arg1[0], arg2[0], 0);
260 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x07, 0x00);
263 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x0f, 0x00);
266 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x1f, 0x00);
269 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
276 if (arg2[0] < 0x40) {
279 cgen_2r(LOONG_MOVFR2GR_S, arg1[0], arg2[0] & 0x1f);
282 cgen_2r(LOONG_MOVFR2GR_D, arg1[0], arg2[0] & 0x1f);
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);
294 if (imm >= -0x800 && imm < 0x800) {
295 cgen_2ri12(LOONG_ADDI_D, arg1[0], R_ZERO, imm);
298 if (!(imm & 0xfff) && imm == (int32_t)imm) {
299 cgen_1ri20(LOONG_LU12I_W, arg1[0], (uint64_t)imm >> 12);
302 if (!(imm & 0x000fffffffffffffLL)) {
303 cgen_2ri12(LOONG_LU52I_D, arg1[0], R_ZERO, (uint64_t)imm >> 52);
308 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
310 return cgen_ld_st(ctx, ld_unsigned, size, arg1[0], arg2);
312 return cgen_ld_st(ctx, ld_signed, size, arg1[0], arg2);
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);
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);
327 if (arg2[0] < 0x40) {
328 return cgen_ld_st(ctx, st_fp, size, arg2[0] & 0x1f, arg1);
330 if (arg2[0] == ARG_IMM) {
331 imm = get_imm(&arg2[1]);
332 if (unlikely(imm != 0))
334 return cgen_ld_st(ctx, st, size, R_ZERO, arg1);
339 internal(file_line, "cgen_mov: invalid arguments %02x, %02x", arg1[0], arg2[0]);
343 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
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);
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);
361 cgen_2ri12(mc, arg1[0], arg2[0], imm);
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");
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);
378 uint8_t *argx = arg2;
382 cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
386 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
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;
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);
404 if (unlikely(imm < 0) || unlikely(imm >= 0x1000))
405 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
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);
414 cgen_2ri12(mc, arg1[0], arg2[0], imm);
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);
434 cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
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);
445 cgen_3r(LOONG_NOR, arg1[0], R_ZERO, arg2[0]);
448 cgen_3r(size == OP_SIZE_4 ? LOONG_SUB_W : LOONG_SUB_D, arg1[0], R_ZERO, arg2[0]);
451 cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], 1);
454 cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], -1);
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);
462 cgen_2r(LOONG_REVB_4H, arg1[0], arg2[0]);
463 cgen_2r(LOONG_REVH_D, arg1[0], arg1[0]);
467 cgen_2r(size == OP_SIZE_4 ? LOONG_REVB_2H : LOONG_REVB_4H, arg1[0], arg2[0]);
470 cgen_2r(size == OP_SIZE_4 ? LOONG_BITREV_W : LOONG_BITREV_D, arg1[0], arg2[0]);
473 cgen_2r(size == OP_SIZE_4 ? LOONG_CTZ_W : LOONG_CTZ_D, arg1[0], arg2[0]);
476 cgen_2r(size == OP_SIZE_4 ? LOONG_CLZ_W : LOONG_CLZ_D, arg1[0], arg2[0]);
479 internal(file_line, "cgen_alu1: invalid alu %u", alu);
484 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
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]);
494 imm = -(uint64_t)imm;
495 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
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);
504 cgen_2ri8(mc, arg1[0], arg2[0], imm);
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);
514 cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
518 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
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))
527 imm = get_imm(&arg3[1]) & 0x3f;
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);
535 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], imm, imm);
540 internal(file_line, "cgen_btx: bad arguments: %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
544 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
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))
554 imm = get_imm(&arg3[1]);
558 if (unlikely(arg1[0] != arg2[0]))
560 cgen_1ri20(LOONG_LU32I_D, arg1[0], imm);
563 cgen_2ri12(LOONG_LU52I_D, arg1[0], arg2[0], imm);
565 default: goto invalid;
569 internal(file_line, "cgen_mov_mask: bad arguments: %02x, %02x, %u, %"PRIxMAX"", arg1[0], arg2[0], aux, (uintmax_t)imm);
573 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
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;
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);
597 uint8_t *argx = arg1;
602 cgen_3r(mc, 0, arg1[0] & 0x1f, arg2[0] & 0x1f);
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);
613 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
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);
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);
627 cgen_3r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f, arg3[0] & 0x1f);
631 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
634 uint8_t *arg1 = ctx->code_position;
635 uint8_t *arg2 = arg1 + arg_size(*arg1);
636 ctx->code_position = arg2 + arg_size(*arg2);
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);
643 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
647 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
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;
661 mc = LOONG_FTINTRZ_W_D;
663 if (fp_op_size == OP_SIZE_4)
664 mc = LOONG_FTINTRZ_L_S;
666 mc = LOONG_FTINTRZ_L_D;
668 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
672 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
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;
686 mc = LOONG_FFINT_D_W;
688 if (fp_op_size == OP_SIZE_4)
689 mc = LOONG_FFINT_S_L;
691 mc = LOONG_FFINT_D_L;
693 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
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);
704 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
709 if (reg1 >= 0x20 || reg2 >= 0x20)
712 if (length > JMP_SHORTEST)
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;
732 unsigned regx = reg1;
737 if (length == JMP_SHORTEST) {
738 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
739 cgen_2ri16(mc, reg2, reg1, 0);
742 cgen_2ri16(mc, reg2, reg1, 2);
743 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
744 cgen_i26(LOONG_B, 0);
749 internal(file_line, "cgen_jmp_12regs: invalid arguments %02x, %02x", reg1, reg2);
753 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
756 uint8_t *arg1 = ctx->code_position;
757 ctx->code_position = arg1 + arg_size(*arg1);
764 g(cgen_jmp_12regs(ctx, COND_L, length, arg1[0], R_ZERO, 1));
768 g(cgen_jmp_12regs(ctx, COND_GE, length, arg1[0], R_ZERO, 1));
772 g(cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1));
776 if (length > JMP_SHORT)
780 case COND_E: mc = LOONG_BEQZ; break;
781 case COND_NE: mc = LOONG_BNEZ; break;
782 default: goto invalid;
785 if (length <= JMP_SHORT) {
786 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
787 cgen_1ri21(mc, arg1[0], 0);
790 cgen_1ri21(mc, arg1[0], 2);
791 g(add_relocation(ctx, JMP_LONG, 1, NULL));
792 cgen_i26(LOONG_B, 0);
797 internal(file_line, "cgen_jmp_reg: invalid argument %02x, %u", arg1[0], cond);
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));
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);
817 cgen_1ri21(LOONG_BCEQZ, 0, 2);
818 g(add_relocation(ctx, JMP_LONG, 0, NULL));
819 cgen_i26(LOONG_B, 0);
824 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
827 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
828 switch (reloc->length) {
830 if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
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);
838 if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
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);
846 if (unlikely(offs < -0x2000000) || unlikely(offs >= 0x2000000))
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);
854 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
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))
865 /*debug("insn: %08x", (unsigned)insn);*/
866 switch (insn_opcode(insn)) {
874 cgen_2ri16(LOONG_JIRL, R_ZERO, R_RA, 0);
876 case INSN_CALL_INDIRECT:
877 g(cgen_jmp_call_indirect(ctx, true));
880 g(cgen_mov(ctx, insn_op_size(insn), false));
883 g(cgen_mov(ctx, insn_op_size(insn), true));
885 case INSN_CMP_DEST_REG:
886 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
888 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
891 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
893 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
896 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
898 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
901 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
903 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
906 g(cgen_btx(ctx, insn_aux(insn)));
909 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
911 g(cgen_mov_mask(ctx, insn_aux(insn)));
913 case INSN_FP_CMP_COND:
914 g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
916 case INSN_FP_TEST_REG:
917 g(cgen_fp_test_reg(ctx));
920 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
923 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
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)));
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)));
937 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
939 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
942 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
944 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
946 case INSN_JMP_FP_TEST:
947 g(cgen_jmp_fp_test(ctx, insn_jump_size(insn)));
949 case INSN_JMP_INDIRECT:
950 g(cgen_jmp_call_indirect(ctx, false));
954 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);