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_FMOV_S 0x01149400U
96 #define LOONG_FMOV_D 0x01149800U
97 #define LOONG_MOVFR2GR_S 0x0114b400U
98 #define LOONG_MOVFR2GR_D 0x0114b800U
99 #define LOONG_MOVCF2GR 0x0114dc00U
100 #define LOONG_FTINTRZ_W_S 0x011a8400U
101 #define LOONG_FTINTRZ_W_D 0x011a8800U
102 #define LOONG_FTINTRZ_L_S 0x011aa400U
103 #define LOONG_FTINTRZ_L_D 0x011aa800U
104 #define LOONG_FFINT_S_W 0x011d1000U
105 #define LOONG_FFINT_S_L 0x011d1800U
106 #define LOONG_FFINT_D_W 0x011d2000U
107 #define LOONG_FFINT_D_L 0x011d2800U
108 #define LOONG_FRINT_S 0x011e4400U
109 #define LOONG_FRINT_D 0x011e4800U
110 #define LOONG_SLTI 0x02000000U
111 #define LOONG_SLTUI 0x02400000U
112 #define LOONG_ADDI_W 0x02800000U
113 #define LOONG_ADDI_D 0x02c00000U
114 #define LOONG_LU52I_D 0x03000000U
115 #define LOONG_ANDI 0x03400000U
116 #define LOONG_ORI 0x03800000U
117 #define LOONG_XORI 0x03c00000U
118 #define LOONG_FCMP_S 0x0c100000U
119 #define LOONG_FCMP_D 0x0c200000U
120 #define LOONG_FCMP_SIG 0x00008000U
121 #define LOONG_FCMP_AF 0x00000000U
122 #define LOONG_FCMP_LT 0x00010000U
123 #define LOONG_FCMP_EQ 0x00020000U
124 #define LOONG_FCMP_LE 0x00030000U
125 #define LOONG_FCMP_UN 0x00040000U
126 #define LOONG_FCMP_ULT 0x00050000U
127 #define LOONG_FCMP_UEQ 0x00060000U
128 #define LOONG_FCMP_ULE 0x00070000U
129 #define LOONG_FCMP_NE 0x00080000U
130 #define LOONG_FCMP_OR 0x000a0000U
131 #define LOONG_FCMP_UNE 0x000c0000U
132 #define LOONG_MOVGR2FR_W 0x0114a400U
133 #define LOONG_MOVGR2FR_D 0x0114a800U
134 #define LOONG_LU12I_W 0x14000000U
135 #define LOONG_LU32I_D 0x16000000U
136 #define LOONG_LDPTR_W 0x24000000U
137 #define LOONG_LDPTR_D 0x26000000U
138 #define LOONG_STPTR_W 0x25000000U
139 #define LOONG_STPTR_D 0x27000000U
140 #define LOONG_LD_B 0x28000000U
141 #define LOONG_LD_H 0x28400000U
142 #define LOONG_LD_W 0x28800000U
143 #define LOONG_LD_D 0x28c00000U
144 #define LOONG_ST_B 0x29000000U
145 #define LOONG_ST_H 0x29400000U
146 #define LOONG_ST_W 0x29800000U
147 #define LOONG_ST_D 0x29c00000U
148 #define LOONG_LD_BU 0x2a000000U
149 #define LOONG_LD_HU 0x2a400000U
150 #define LOONG_LD_WU 0x2a800000U
151 #define LOONG_FLD_S 0x2b000000U
152 #define LOONG_FST_S 0x2b400000U
153 #define LOONG_FLD_D 0x2b800000U
154 #define LOONG_FST_D 0x2bc00000U
155 #define LOONG_LDX_B 0x38000000U
156 #define LOONG_LDX_H 0x38040000U
157 #define LOONG_LDX_W 0x38080000U
158 #define LOONG_LDX_D 0x380c0000U
159 #define LOONG_STX_B 0x38100000U
160 #define LOONG_STX_H 0x38140000U
161 #define LOONG_STX_W 0x38180000U
162 #define LOONG_STX_D 0x381c0000U
163 #define LOONG_LDX_BU 0x38200000U
164 #define LOONG_LDX_HU 0x38240000U
165 #define LOONG_LDX_WU 0x38280000U
166 #define LOONG_FLDX_S 0x38300000U
167 #define LOONG_FLDX_D 0x38340000U
168 #define LOONG_FSTX_S 0x38380000U
169 #define LOONG_FSTX_D 0x383c0000U
170 #define LOONG_BEQZ 0x40000000U
171 #define LOONG_BNEZ 0x44000000U
172 #define LOONG_BCEQZ 0x48000000U
173 #define LOONG_BCNEZ 0x48000100U
174 #define LOONG_JIRL 0x4c000000U
175 #define LOONG_B 0x50000000U
176 #define LOONG_BEQ 0x58000000U
177 #define LOONG_BNE 0x5c000000U
178 #define LOONG_BLT 0x60000000U
179 #define LOONG_BGE 0x64000000U
180 #define LOONG_BLTU 0x68000000U
181 #define LOONG_BGEU 0x6c000000U
184 #define cgen_i26(opcode, imm) cgen_four((opcode) | ((imm) & 0xffffU) << 10 | ((imm) & 0x3ff0000) >> 16)
185 #define cgen_1ri20(opcode, rd, imm) cgen_four((opcode) | (rd) | ((imm) & 0xFFFFFU) << 5)
186 #define cgen_1ri21(opcode, rj, imm) cgen_four((opcode) | (rj) << 5 | ((imm) & 0xFFFFU) << 5 | ((imm) & 0x1f0000) >> 16)
187 #define cgen_2r(opcode, rd, rj) cgen_four((opcode) | (rd) | (rj) << 5)
188 #define cgen_2ri8(opcode, rd, rj, imm) cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xffU) << 10)
189 #define cgen_2ri12(opcode, rd, rj, imm) cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xfffU) << 10)
190 #define cgen_2ri14(opcode, rd, rj, imm) cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0x3fffU) << 10)
191 #define cgen_2ri16(opcode, rd, rj, imm) cgen_four((opcode) | (rd) | (rj) << 5 | ((imm) & 0xffffU) << 10)
192 #define cgen_2r2i(opcode, rd, rj, imm_m, imm_l) cgen_four((opcode) | (rd) | (rj) << 5 | (imm_m) << 16 | (imm_l) << 10)
193 #define cgen_3r(opcode, rd, rj, rk) cgen_four((opcode) | (rd) | (rj) << 5 | ((rk) << 10))
195 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, bool call)
197 uint8_t reg = cget_one(ctx);
198 uint8_t save = call ? R_RA : R_ZERO;
199 cgen_2ri16(LOONG_JIRL, save, reg, 0);
203 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 };
204 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 };
205 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 };
206 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 };
207 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 };
209 static bool cgen_ld_st(struct codegen_context *ctx, const uint32_t table[10], unsigned size, uint8_t reg, uint8_t *address)
212 if (address[0] == ARG_ADDRESS_1) {
213 imm = get_imm(&address[2]);
214 if (!(imm & 3) && imm >= -0x8000 && imm < 0x8000 && (size == OP_SIZE_4 || size == OP_SIZE_8)) {
215 uint32_t mc = table[8 + size - OP_SIZE_4];
217 cgen_2ri14(mc, reg, address[1], (uint64_t)imm >> 2);
221 if (imm >= -0x800 && imm < 0x800) {
222 cgen_2ri12(table[size], reg, address[1], imm);
225 } else if (address[0] == ARG_ADDRESS_2) {
226 imm = get_imm(&address[3]);
227 if (unlikely(imm != 0))
229 cgen_3r(table[4 + size], reg, address[1], address[2]);
233 internal(file_line, "cgen_ld_st: invalid arguments %02x, %02x", reg, address[0]);
237 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
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 (size == OP_SIZE_NATIVE)
245 if (arg1[0] < 0x20) {
246 if (arg2[0] < 0x20) {
250 cgen_2r(LOONG_EXT_W_B, arg1[0], arg2[0]);
253 cgen_2r(LOONG_EXT_W_H, arg1[0], arg2[0]);
256 cgen_2ri8(LOONG_SLLI_W, arg1[0], arg2[0], 0);
264 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x07, 0x00);
267 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x0f, 0x00);
270 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], 0x1f, 0x00);
273 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
280 if (reg_is_fp(arg2[0])) {
283 cgen_2r(LOONG_MOVFR2GR_S, arg1[0], arg2[0] & 0x1f);
286 cgen_2r(LOONG_MOVFR2GR_D, arg1[0], arg2[0] & 0x1f);
292 if (arg2[0] == ARG_IMM) {
293 imm = get_imm(&arg2[1]);
294 if (imm >= 0 && imm < 0x1000) {
295 cgen_2ri12(LOONG_ORI, arg1[0], R_ZERO, imm);
298 if (imm >= -0x800 && imm < 0x800) {
299 cgen_2ri12(LOONG_ADDI_D, arg1[0], R_ZERO, imm);
302 if (!(imm & 0xfff) && imm == (int32_t)imm) {
303 cgen_1ri20(LOONG_LU12I_W, arg1[0], (uint64_t)imm >> 12);
306 if (!(imm & 0x000fffffffffffffLL)) {
307 cgen_2ri12(LOONG_LU52I_D, arg1[0], R_ZERO, (uint64_t)imm >> 52);
312 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
314 return cgen_ld_st(ctx, ld_unsigned, size, arg1[0], arg2);
316 return cgen_ld_st(ctx, ld_signed, size, arg1[0], arg2);
321 if (reg_is_fp(arg1[0])) {
322 if (arg2[0] < 0x20) {
325 cgen_2r(LOONG_MOVGR2FR_W, arg1[0] & 0x1f, arg2[0]);
328 cgen_2r(LOONG_MOVGR2FR_D, arg1[0] & 0x1f, arg2[0]);
334 if (reg_is_fp(arg2[0])) {
337 cgen_2r(LOONG_FMOV_S, arg1[0] & 0x1f, arg2[0] & 0x1f);
340 cgen_2r(LOONG_FMOV_D, arg1[0] & 0x1f, arg2[0] & 0x1f);
346 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
347 return cgen_ld_st(ctx, ld_fp, size, arg1[0] & 0x1f, arg2);
351 if (arg1[0] == ARG_ADDRESS_1 || arg1[0] == ARG_ADDRESS_2) {
352 if (arg2[0] < 0x20) {
353 return cgen_ld_st(ctx, st, size, arg2[0], arg1);
355 if (reg_is_fp(arg2[0])) {
356 return cgen_ld_st(ctx, st_fp, size, arg2[0] & 0x1f, arg1);
358 if (arg2[0] == ARG_IMM) {
359 imm = get_imm(&arg2[1]);
360 if (unlikely(imm != 0))
362 return cgen_ld_st(ctx, st, size, R_ZERO, arg1);
367 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
371 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
376 uint8_t *arg1 = ctx->code_position;
377 uint8_t *arg2 = arg1 + arg_size(*arg1);
378 uint8_t *arg3 = arg2 + arg_size(*arg2);
379 ctx->code_position = arg3 + arg_size(*arg3);
380 if (arg3[0] == ARG_IMM) {
381 int64_t imm = get_imm(&arg3[1]);
382 if (unlikely(imm < -0x800) && unlikely(imm >= 0x800))
383 internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
385 case COND_B: mc = LOONG_SLTUI; break;
386 case COND_L: mc = LOONG_SLTI; break;
387 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
389 cgen_2ri12(mc, arg1[0], arg2[0], imm);
392 if (arg2[0] == ARG_IMM) {
393 int64_t imm = get_imm(&arg2[1]);
394 if (unlikely(imm != 0))
395 internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
399 case COND_B: mc = LOONG_SLTU; break;
400 case COND_A: mc = LOONG_SLTU; swap = true; break;
401 case COND_L: mc = LOONG_SLT; break;
402 case COND_G: mc = LOONG_SLT; swap = true; break;
403 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
406 uint8_t *argx = arg2;
410 cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
414 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
417 uint8_t *arg1 = ctx->code_position;
418 uint8_t *arg2 = arg1 + arg_size(*arg1);
419 uint8_t *arg3 = arg2 + arg_size(*arg2);
420 ctx->code_position = arg3 + arg_size(*arg3);
422 if (arg3[0] == ARG_IMM) {
423 int64_t imm = get_imm(&arg3[1]);
424 if (alu == ALU_SUB) {
425 imm = -(uint64_t)imm;
428 if (alu == ALU_ADD) {
429 if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
430 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
432 if (unlikely(imm < 0) || unlikely(imm >= 0x1000))
433 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
436 case ALU_ADD: mc = size == OP_SIZE_8 ? LOONG_ADDI_D : LOONG_ADDI_W; break;
437 case ALU_XOR: mc = LOONG_XORI; break;
438 case ALU_OR: mc = LOONG_ORI; break;
439 case ALU_AND: mc = LOONG_ANDI; break;
440 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
442 cgen_2ri12(mc, arg1[0], arg2[0], imm);
447 case ALU_ADD: mc = size == OP_SIZE_8 ? LOONG_ADD_D : LOONG_ADD_W; break;
448 case ALU_SUB: mc = size == OP_SIZE_8 ? LOONG_SUB_D : LOONG_SUB_W; break;
449 case ALU_XOR: mc = LOONG_XOR; break;
450 case ALU_OR: mc = LOONG_OR; break;
451 case ALU_AND: mc = LOONG_AND; break;
452 case ALU_ANDN: mc = LOONG_ANDN; break;
453 case ALU_ORN: mc = LOONG_ORN; break;
454 case ALU_MUL: mc = size == OP_SIZE_8 ? LOONG_MUL_D : LOONG_MUL_W; break;
455 case ALU_SMULH: mc = size == OP_SIZE_8 ? LOONG_MULH_D : LOONG_MULH_W; break;
456 case ALU_UDIV: mc = size == OP_SIZE_8 ? LOONG_DIV_DU : LOONG_DIV_WU; break;
457 case ALU_SDIV: mc = size == OP_SIZE_8 ? LOONG_DIV_D : LOONG_DIV_W; break;
458 case ALU_UREM: mc = size == OP_SIZE_8 ? LOONG_MOD_DU : LOONG_MOD_WU; break;
459 case ALU_SREM: mc = size == OP_SIZE_8 ? LOONG_MOD_D : LOONG_MOD_W; break;
460 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
462 cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
466 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
468 uint8_t *arg1 = ctx->code_position;
469 uint8_t *arg2 = arg1 + arg_size(*arg1);
470 ctx->code_position = arg2 + arg_size(*arg2);
473 cgen_3r(LOONG_NOR, arg1[0], R_ZERO, arg2[0]);
476 cgen_3r(size == OP_SIZE_4 ? LOONG_SUB_W : LOONG_SUB_D, arg1[0], R_ZERO, arg2[0]);
479 if (size == OP_SIZE_4) {
480 cgen_2r(LOONG_REVB_2H, arg1[0], arg2[0]);
481 cgen_2ri8(LOONG_ROTRI_W, arg1[0], arg1[0], 0x10);
484 cgen_2r(LOONG_REVB_4H, arg1[0], arg2[0]);
485 cgen_2r(LOONG_REVH_D, arg1[0], arg1[0]);
489 cgen_2r(size == OP_SIZE_4 ? LOONG_REVB_2H : LOONG_REVB_4H, arg1[0], arg2[0]);
492 cgen_2r(size == OP_SIZE_4 ? LOONG_BITREV_W : LOONG_BITREV_D, arg1[0], arg2[0]);
495 cgen_2r(size == OP_SIZE_4 ? LOONG_CTZ_W : LOONG_CTZ_D, arg1[0], arg2[0]);
498 cgen_2r(size == OP_SIZE_4 ? LOONG_CLZ_W : LOONG_CLZ_D, arg1[0], arg2[0]);
501 internal(file_line, "cgen_alu1: invalid alu %u", alu);
506 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
509 uint8_t *arg1 = ctx->code_position;
510 uint8_t *arg2 = arg1 + arg_size(*arg1);
511 uint8_t *arg3 = arg2 + arg_size(*arg2);
512 ctx->code_position = arg3 + arg_size(*arg3);
513 if (arg3[0] == ARG_IMM) {
514 int64_t imm = get_imm(&arg3[1]);
516 imm = -(uint64_t)imm;
517 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
519 case ROT_ROL: mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
520 case ROT_ROR: mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
521 case ROT_SHL: mc = size == OP_SIZE_4 ? LOONG_SLLI_W : LOONG_SLLI_D; break;
522 case ROT_SHR: mc = size == OP_SIZE_4 ? LOONG_SRLI_W : LOONG_SRLI_D; break;
523 case ROT_SAR: mc = size == OP_SIZE_4 ? LOONG_SRAI_W : LOONG_SRAI_D; break;
524 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
526 cgen_2ri8(mc, arg1[0], arg2[0], imm);
530 case ROT_ROR: mc = size == OP_SIZE_4 ? LOONG_ROTR_W : LOONG_ROTR_D; break;
531 case ROT_SHL: mc = size == OP_SIZE_4 ? LOONG_SLL_W : LOONG_SLL_D; break;
532 case ROT_SHR: mc = size == OP_SIZE_4 ? LOONG_SRL_W : LOONG_SRL_D; break;
533 case ROT_SAR: mc = size == OP_SIZE_4 ? LOONG_SRA_W : LOONG_SRA_D; break;
534 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
536 cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
540 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
543 uint8_t *arg1 = ctx->code_position;
544 uint8_t *arg2 = arg1 + arg_size(*arg1);
545 uint8_t *arg3 = arg2 + arg_size(*arg2);
546 ctx->code_position = arg3 + arg_size(*arg3);
547 if (unlikely(arg3[0] != ARG_IMM))
549 imm = get_imm(&arg3[1]) & 0x3f;
552 if (unlikely(arg1[0] != arg2[0]))
553 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
554 cgen_2r2i(LOONG_BSTRINS_D, arg1[0], R_ZERO, imm, imm);
557 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], imm, imm);
562 internal(file_line, "cgen_btx: bad arguments: %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
566 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
569 uint8_t *arg1 = ctx->code_position;
570 uint8_t *arg2 = arg1 + arg_size(*arg1);
571 uint8_t *arg3 = arg2 + arg_size(*arg2);
572 ctx->code_position = arg3 + arg_size(*arg3);
573 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] != ARG_IMM))
576 imm = get_imm(&arg3[1]);
580 if (unlikely(arg1[0] != arg2[0]))
582 cgen_1ri20(LOONG_LU32I_D, arg1[0], imm);
585 cgen_2ri12(LOONG_LU52I_D, arg1[0], arg2[0], imm);
587 default: goto invalid;
591 internal(file_line, "cgen_mov_mask: bad arguments: %02x, %02x, %u, %"PRIxMAX"", arg1[0], arg2[0], aux, (uintmax_t)imm);
595 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
599 uint8_t *arg1 = ctx->code_position;
600 uint8_t *arg2 = arg1 + arg_size(*arg1);
601 ctx->code_position = arg2 + arg_size(*arg2);
603 mc = op_size == OP_SIZE_4 ? LOONG_FCMP_S : LOONG_FCMP_D;
606 case FP_COND_P: mc |= LOONG_FCMP_UN; swap = false; break;
607 case FP_COND_NP: mc |= LOONG_FCMP_OR; swap = false; break;
608 case FP_COND_E: mc |= LOONG_FCMP_EQ; swap = false; break;
609 case FP_COND_NE: mc |= LOONG_FCMP_NE; swap = false; break;
610 case FP_COND_A: mc |= LOONG_FCMP_LT; swap = true; break;
611 case FP_COND_BE: mc |= LOONG_FCMP_LE; swap = false; break;
612 case FP_COND_B: mc |= LOONG_FCMP_LT; swap = false; break;
613 case FP_COND_AE: mc |= LOONG_FCMP_LE; swap = true; break;
614 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
619 uint8_t *argx = arg1;
624 cgen_3r(mc, 0, arg1[0] & 0x1f, arg2[0] & 0x1f);
628 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx)
630 unsigned reg = cget_one(ctx);
631 cgen_2r(LOONG_MOVCF2GR, reg, 0);
635 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
638 uint8_t *arg1 = ctx->code_position;
639 uint8_t *arg2 = arg1 + arg_size(*arg1);
640 uint8_t *arg3 = arg2 + arg_size(*arg2);
641 ctx->code_position = arg3 + arg_size(*arg3);
643 case FP_ALU_ADD: mc = op_size == OP_SIZE_4 ? LOONG_FADD_S : LOONG_FADD_D; break;
644 case FP_ALU_SUB: mc = op_size == OP_SIZE_4 ? LOONG_FSUB_S : LOONG_FSUB_D; break;
645 case FP_ALU_MUL: mc = op_size == OP_SIZE_4 ? LOONG_FMUL_S : LOONG_FMUL_D; break;
646 case FP_ALU_DIV: mc = op_size == OP_SIZE_4 ? LOONG_FDIV_S : LOONG_FDIV_D; break;
647 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
649 cgen_3r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f, arg3[0] & 0x1f);
653 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
656 uint8_t *arg1 = ctx->code_position;
657 uint8_t *arg2 = arg1 + arg_size(*arg1);
658 ctx->code_position = arg2 + arg_size(*arg2);
660 case FP_ALU1_NEG: mc = op_size == OP_SIZE_4 ? LOONG_FNEG_S : LOONG_FNEG_D; break;
661 case FP_ALU1_SQRT: mc = op_size == OP_SIZE_4 ? LOONG_FSQRT_S : LOONG_FSQRT_D; break;
662 case FP_ALU1_ROUND: mc = op_size == OP_SIZE_4 ? LOONG_FRINT_S : LOONG_FRINT_D; break;
663 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
665 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
669 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
672 uint8_t *arg1 = ctx->code_position;
673 uint8_t *arg2 = arg1 + arg_size(*arg1);
674 ctx->code_position = arg2 + arg_size(*arg2);
676 if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
677 internal(file_line, "cgen_fp_to_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
679 if (int_op_size == OP_SIZE_4) {
680 if (fp_op_size == OP_SIZE_4)
681 mc = LOONG_FTINTRZ_W_S;
683 mc = LOONG_FTINTRZ_W_D;
685 if (fp_op_size == OP_SIZE_4)
686 mc = LOONG_FTINTRZ_L_S;
688 mc = LOONG_FTINTRZ_L_D;
690 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
694 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
697 uint8_t *arg1 = ctx->code_position;
698 uint8_t *arg2 = arg1 + arg_size(*arg1);
699 ctx->code_position = arg2 + arg_size(*arg2);
701 if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
702 internal(file_line, "cgen_fp_from_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
704 if (int_op_size == OP_SIZE_4) {
705 if (fp_op_size == OP_SIZE_4)
706 mc = LOONG_FFINT_S_W;
708 mc = LOONG_FFINT_D_W;
710 if (fp_op_size == OP_SIZE_4)
711 mc = LOONG_FFINT_S_L;
713 mc = LOONG_FFINT_D_L;
715 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
719 static bool attr_w cgen_jmp(struct codegen_context *ctx)
721 g(add_relocation(ctx, JMP_LONG, 0, NULL));
722 cgen_i26(LOONG_B, 0);
726 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
731 if (reg1 >= 0x20 || reg2 >= 0x20)
734 if (length > JMP_SHORTEST)
739 case COND_B: mc = LOONG_BLTU; break;
740 case COND_AE: mc = LOONG_BGEU; break;
741 case COND_E: mc = LOONG_BEQ; break;
742 case COND_NE: mc = LOONG_BNE; break;
743 case COND_BE: mc = LOONG_BGEU; swap = true; break;
744 case COND_A: mc = LOONG_BLTU; swap = true; break;
745 case COND_L: mc = LOONG_BLT; break;
746 case COND_GE: mc = LOONG_BGE; break;
747 case COND_LE: mc = LOONG_BGE; swap = true; break;
748 case COND_G: mc = LOONG_BLT; swap = true; break;
749 default: goto invalid;
754 unsigned regx = reg1;
759 if (length == JMP_SHORTEST) {
760 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
761 cgen_2ri16(mc, reg2, reg1, 0);
764 cgen_2ri16(mc, reg2, reg1, 2);
765 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
766 cgen_i26(LOONG_B, 0);
771 internal(file_line, "cgen_jmp_12regs: invalid arguments %02x, %02x", reg1, reg2);
775 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
778 uint8_t *arg1 = ctx->code_position;
779 ctx->code_position = arg1 + arg_size(*arg1);
786 g(cgen_jmp_12regs(ctx, COND_L, length, arg1[0], R_ZERO, 1));
790 g(cgen_jmp_12regs(ctx, COND_GE, length, arg1[0], R_ZERO, 1));
794 g(cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1));
798 if (length > JMP_SHORT)
802 case COND_E: mc = LOONG_BEQZ; break;
803 case COND_NE: mc = LOONG_BNEZ; break;
804 default: goto invalid;
807 if (length <= JMP_SHORT) {
808 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
809 cgen_1ri21(mc, arg1[0], 0);
812 cgen_1ri21(mc, arg1[0], 2);
813 g(add_relocation(ctx, JMP_LONG, 1, NULL));
814 cgen_i26(LOONG_B, 0);
819 internal(file_line, "cgen_jmp_reg: invalid argument %02x, %u", arg1[0], cond);
823 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
825 uint8_t *arg1 = ctx->code_position;
826 uint8_t *arg2 = arg1 + arg_size(*arg1);
827 ctx->code_position = arg2 + arg_size(*arg2);
828 g(cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2));
832 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned length)
834 if (length <= JMP_SHORT) {
835 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
836 cgen_1ri21(LOONG_BCNEZ, 0, 0);
839 cgen_1ri21(LOONG_BCEQZ, 0, 2);
840 g(add_relocation(ctx, JMP_LONG, 0, NULL));
841 cgen_i26(LOONG_B, 0);
846 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
849 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
850 switch (reloc->length) {
852 if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
854 memcpy(&mc, ctx->mcode + reloc->position, 4);
855 mc &= ~(0xffffU << 10);
856 mc |= (offs & 0xffffU) << 10;
857 memcpy(ctx->mcode + reloc->position, &mc, 4);
860 if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
862 memcpy(&mc, ctx->mcode + reloc->position, 4);
863 mc &= ~((0xffffU << 10) | 0x1fU);
864 mc |= ((offs & 0xffffU) << 10) | ((offs & 0x1f0000U) >> 16);
865 memcpy(ctx->mcode + reloc->position, &mc, 4);
868 if (unlikely(offs < -0x2000000) || unlikely(offs >= 0x2000000))
870 memcpy(&mc, ctx->mcode + reloc->position, 4);
871 mc &= ~((0xffffU << 10) | 0x3ffU);
872 mc |= ((offs & 0xffffU) << 10) | ((offs & 0x3ff0000U) >> 16);
873 memcpy(ctx->mcode + reloc->position, &mc, 4);
876 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
881 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
883 if (unlikely(insn_writes_flags(insn))) {
884 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
887 /*debug("insn: %08x", (unsigned)insn);*/
888 switch (insn_opcode(insn)) {
896 cgen_2ri16(LOONG_JIRL, R_ZERO, R_RA, 0);
898 case INSN_CALL_INDIRECT:
899 g(cgen_jmp_call_indirect(ctx, true));
902 g(cgen_mov(ctx, insn_op_size(insn), false));
905 g(cgen_mov(ctx, insn_op_size(insn), true));
907 case INSN_CMP_DEST_REG:
908 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
910 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
913 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
915 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
918 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
920 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
923 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
925 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
928 g(cgen_btx(ctx, insn_aux(insn)));
931 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
933 g(cgen_mov_mask(ctx, insn_aux(insn)));
935 case INSN_FP_CMP_COND:
936 g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
938 case INSN_FP_TEST_REG:
939 g(cgen_fp_test_reg(ctx));
942 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
945 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
947 case INSN_FP_TO_INT32:
948 case INSN_FP_TO_INT64:
949 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
951 case INSN_FP_FROM_INT32:
952 case INSN_FP_FROM_INT64:
953 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
959 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
961 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
964 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
966 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
968 case INSN_JMP_FP_TEST:
969 g(cgen_jmp_fp_test(ctx, insn_jump_size(insn)));
971 case INSN_JMP_INDIRECT:
972 g(cgen_jmp_call_indirect(ctx, false));
976 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);