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 cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], 1);
482 cgen_2ri12(size == OP_SIZE_4 ? LOONG_ADDI_W : LOONG_ADDI_D, arg1[0], arg2[0], -1);
485 if (size == OP_SIZE_4) {
486 cgen_2r(LOONG_REVB_2H, arg1[0], arg2[0]);
487 cgen_2ri8(LOONG_ROTRI_W, arg1[0], arg1[0], 0x10);
490 cgen_2r(LOONG_REVB_4H, arg1[0], arg2[0]);
491 cgen_2r(LOONG_REVH_D, arg1[0], arg1[0]);
495 cgen_2r(size == OP_SIZE_4 ? LOONG_REVB_2H : LOONG_REVB_4H, arg1[0], arg2[0]);
498 cgen_2r(size == OP_SIZE_4 ? LOONG_BITREV_W : LOONG_BITREV_D, arg1[0], arg2[0]);
501 cgen_2r(size == OP_SIZE_4 ? LOONG_CTZ_W : LOONG_CTZ_D, arg1[0], arg2[0]);
504 cgen_2r(size == OP_SIZE_4 ? LOONG_CLZ_W : LOONG_CLZ_D, arg1[0], arg2[0]);
507 internal(file_line, "cgen_alu1: invalid alu %u", alu);
512 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
515 uint8_t *arg1 = ctx->code_position;
516 uint8_t *arg2 = arg1 + arg_size(*arg1);
517 uint8_t *arg3 = arg2 + arg_size(*arg2);
518 ctx->code_position = arg3 + arg_size(*arg3);
519 if (arg3[0] == ARG_IMM) {
520 int64_t imm = get_imm(&arg3[1]);
522 imm = -(uint64_t)imm;
523 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
525 case ROT_ROL: mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
526 case ROT_ROR: mc = size == OP_SIZE_4 ? LOONG_ROTRI_W : LOONG_ROTRI_D; break;
527 case ROT_SHL: mc = size == OP_SIZE_4 ? LOONG_SLLI_W : LOONG_SLLI_D; break;
528 case ROT_SHR: mc = size == OP_SIZE_4 ? LOONG_SRLI_W : LOONG_SRLI_D; break;
529 case ROT_SAR: mc = size == OP_SIZE_4 ? LOONG_SRAI_W : LOONG_SRAI_D; break;
530 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
532 cgen_2ri8(mc, arg1[0], arg2[0], imm);
536 case ROT_ROR: mc = size == OP_SIZE_4 ? LOONG_ROTR_W : LOONG_ROTR_D; break;
537 case ROT_SHL: mc = size == OP_SIZE_4 ? LOONG_SLL_W : LOONG_SLL_D; break;
538 case ROT_SHR: mc = size == OP_SIZE_4 ? LOONG_SRL_W : LOONG_SRL_D; break;
539 case ROT_SAR: mc = size == OP_SIZE_4 ? LOONG_SRA_W : LOONG_SRA_D; break;
540 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
542 cgen_3r(mc, arg1[0], arg2[0], arg3[0]);
546 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
549 uint8_t *arg1 = ctx->code_position;
550 uint8_t *arg2 = arg1 + arg_size(*arg1);
551 uint8_t *arg3 = arg2 + arg_size(*arg2);
552 ctx->code_position = arg3 + arg_size(*arg3);
553 if (unlikely(arg3[0] != ARG_IMM))
555 imm = get_imm(&arg3[1]) & 0x3f;
558 if (unlikely(arg1[0] != arg2[0]))
559 cgen_3r(LOONG_OR, arg1[0], arg2[0], R_ZERO);
560 cgen_2r2i(LOONG_BSTRINS_D, arg1[0], R_ZERO, imm, imm);
563 cgen_2r2i(LOONG_BSTRPICK_D, arg1[0], arg2[0], imm, imm);
568 internal(file_line, "cgen_btx: bad arguments: %02x, %02x, %02x, %u", arg1[0], arg2[0], arg3[0], alu);
572 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
575 uint8_t *arg1 = ctx->code_position;
576 uint8_t *arg2 = arg1 + arg_size(*arg1);
577 uint8_t *arg3 = arg2 + arg_size(*arg2);
578 ctx->code_position = arg3 + arg_size(*arg3);
579 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(arg3[0] != ARG_IMM))
582 imm = get_imm(&arg3[1]);
586 if (unlikely(arg1[0] != arg2[0]))
588 cgen_1ri20(LOONG_LU32I_D, arg1[0], imm);
591 cgen_2ri12(LOONG_LU52I_D, arg1[0], arg2[0], imm);
593 default: goto invalid;
597 internal(file_line, "cgen_mov_mask: bad arguments: %02x, %02x, %u, %"PRIxMAX"", arg1[0], arg2[0], aux, (uintmax_t)imm);
601 static bool attr_w cgen_fp_cmp_cond(struct codegen_context *ctx, unsigned op_size, unsigned aux)
605 uint8_t *arg1 = ctx->code_position;
606 uint8_t *arg2 = arg1 + arg_size(*arg1);
607 ctx->code_position = arg2 + arg_size(*arg2);
609 mc = op_size == OP_SIZE_4 ? LOONG_FCMP_S : LOONG_FCMP_D;
612 case FP_COND_P: mc |= LOONG_FCMP_UN; swap = false; break;
613 case FP_COND_NP: mc |= LOONG_FCMP_OR; swap = false; break;
614 case FP_COND_E: mc |= LOONG_FCMP_EQ; swap = false; break;
615 case FP_COND_NE: mc |= LOONG_FCMP_NE; swap = false; break;
616 case FP_COND_A: mc |= LOONG_FCMP_LT; swap = true; break;
617 case FP_COND_BE: mc |= LOONG_FCMP_LE; swap = false; break;
618 case FP_COND_B: mc |= LOONG_FCMP_LT; swap = false; break;
619 case FP_COND_AE: mc |= LOONG_FCMP_LE; swap = true; break;
620 default: internal(file_line, "cgen_fp_cmp_cond: invalid condition %u", aux);
625 uint8_t *argx = arg1;
630 cgen_3r(mc, 0, arg1[0] & 0x1f, arg2[0] & 0x1f);
634 static bool attr_w cgen_fp_test_reg(struct codegen_context *ctx)
636 unsigned reg = cget_one(ctx);
637 cgen_2r(LOONG_MOVCF2GR, reg, 0);
641 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
644 uint8_t *arg1 = ctx->code_position;
645 uint8_t *arg2 = arg1 + arg_size(*arg1);
646 uint8_t *arg3 = arg2 + arg_size(*arg2);
647 ctx->code_position = arg3 + arg_size(*arg3);
649 case FP_ALU_ADD: mc = op_size == OP_SIZE_4 ? LOONG_FADD_S : LOONG_FADD_D; break;
650 case FP_ALU_SUB: mc = op_size == OP_SIZE_4 ? LOONG_FSUB_S : LOONG_FSUB_D; break;
651 case FP_ALU_MUL: mc = op_size == OP_SIZE_4 ? LOONG_FMUL_S : LOONG_FMUL_D; break;
652 case FP_ALU_DIV: mc = op_size == OP_SIZE_4 ? LOONG_FDIV_S : LOONG_FDIV_D; break;
653 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
655 cgen_3r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f, arg3[0] & 0x1f);
659 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
662 uint8_t *arg1 = ctx->code_position;
663 uint8_t *arg2 = arg1 + arg_size(*arg1);
664 ctx->code_position = arg2 + arg_size(*arg2);
666 case FP_ALU1_NEG: mc = op_size == OP_SIZE_4 ? LOONG_FNEG_S : LOONG_FNEG_D; break;
667 case FP_ALU1_SQRT: mc = op_size == OP_SIZE_4 ? LOONG_FSQRT_S : LOONG_FSQRT_D; break;
668 case FP_ALU1_ROUND: mc = op_size == OP_SIZE_4 ? LOONG_FRINT_S : LOONG_FRINT_D; break;
669 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
671 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
675 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
678 uint8_t *arg1 = ctx->code_position;
679 uint8_t *arg2 = arg1 + arg_size(*arg1);
680 ctx->code_position = arg2 + arg_size(*arg2);
682 if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
683 internal(file_line, "cgen_fp_to_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
685 if (int_op_size == OP_SIZE_4) {
686 if (fp_op_size == OP_SIZE_4)
687 mc = LOONG_FTINTRZ_W_S;
689 mc = LOONG_FTINTRZ_W_D;
691 if (fp_op_size == OP_SIZE_4)
692 mc = LOONG_FTINTRZ_L_S;
694 mc = LOONG_FTINTRZ_L_D;
696 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
700 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
703 uint8_t *arg1 = ctx->code_position;
704 uint8_t *arg2 = arg1 + arg_size(*arg1);
705 ctx->code_position = arg2 + arg_size(*arg2);
707 if (unlikely(!reg_is_fp(arg1[0])) || unlikely(!reg_is_fp(arg2[0])))
708 internal(file_line, "cgen_fp_from_int: invalid registers %02x, %02x", arg1[0], arg2[0]);
710 if (int_op_size == OP_SIZE_4) {
711 if (fp_op_size == OP_SIZE_4)
712 mc = LOONG_FFINT_S_W;
714 mc = LOONG_FFINT_D_W;
716 if (fp_op_size == OP_SIZE_4)
717 mc = LOONG_FFINT_S_L;
719 mc = LOONG_FFINT_D_L;
721 cgen_2r(mc, arg1[0] & 0x1f, arg2[0] & 0x1f);
725 static bool attr_w cgen_jmp(struct codegen_context *ctx)
727 g(add_relocation(ctx, JMP_LONG, 0, NULL));
728 cgen_i26(LOONG_B, 0);
732 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
737 if (reg1 >= 0x20 || reg2 >= 0x20)
740 if (length > JMP_SHORTEST)
745 case COND_B: mc = LOONG_BLTU; break;
746 case COND_AE: mc = LOONG_BGEU; break;
747 case COND_E: mc = LOONG_BEQ; break;
748 case COND_NE: mc = LOONG_BNE; break;
749 case COND_BE: mc = LOONG_BGEU; swap = true; break;
750 case COND_A: mc = LOONG_BLTU; swap = true; break;
751 case COND_L: mc = LOONG_BLT; break;
752 case COND_GE: mc = LOONG_BGE; break;
753 case COND_LE: mc = LOONG_BGE; swap = true; break;
754 case COND_G: mc = LOONG_BLT; swap = true; break;
755 default: goto invalid;
760 unsigned regx = reg1;
765 if (length == JMP_SHORTEST) {
766 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
767 cgen_2ri16(mc, reg2, reg1, 0);
770 cgen_2ri16(mc, reg2, reg1, 2);
771 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
772 cgen_i26(LOONG_B, 0);
777 internal(file_line, "cgen_jmp_12regs: invalid arguments %02x, %02x", reg1, reg2);
781 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
784 uint8_t *arg1 = ctx->code_position;
785 ctx->code_position = arg1 + arg_size(*arg1);
792 g(cgen_jmp_12regs(ctx, COND_L, length, arg1[0], R_ZERO, 1));
796 g(cgen_jmp_12regs(ctx, COND_GE, length, arg1[0], R_ZERO, 1));
800 g(cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1));
804 if (length > JMP_SHORT)
808 case COND_E: mc = LOONG_BEQZ; break;
809 case COND_NE: mc = LOONG_BNEZ; break;
810 default: goto invalid;
813 if (length <= JMP_SHORT) {
814 g(add_relocation(ctx, JMP_SHORT, 1, NULL));
815 cgen_1ri21(mc, arg1[0], 0);
818 cgen_1ri21(mc, arg1[0], 2);
819 g(add_relocation(ctx, JMP_LONG, 1, NULL));
820 cgen_i26(LOONG_B, 0);
825 internal(file_line, "cgen_jmp_reg: invalid argument %02x, %u", arg1[0], cond);
829 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
831 uint8_t *arg1 = ctx->code_position;
832 uint8_t *arg2 = arg1 + arg_size(*arg1);
833 ctx->code_position = arg2 + arg_size(*arg2);
834 g(cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2));
838 static bool attr_w cgen_jmp_fp_test(struct codegen_context *ctx, unsigned length)
840 if (length <= JMP_SHORT) {
841 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
842 cgen_1ri21(LOONG_BCNEZ, 0, 0);
845 cgen_1ri21(LOONG_BCEQZ, 0, 2);
846 g(add_relocation(ctx, JMP_LONG, 0, NULL));
847 cgen_i26(LOONG_B, 0);
852 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
855 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
856 switch (reloc->length) {
858 if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
860 memcpy(&mc, ctx->mcode + reloc->position, 4);
861 mc &= ~(0xffffU << 10);
862 mc |= (offs & 0xffffU) << 10;
863 memcpy(ctx->mcode + reloc->position, &mc, 4);
866 if (unlikely(offs < -0x100000) || unlikely(offs >= 0x100000))
868 memcpy(&mc, ctx->mcode + reloc->position, 4);
869 mc &= ~((0xffffU << 10) | 0x1fU);
870 mc |= ((offs & 0xffffU) << 10) | ((offs & 0x1f0000U) >> 16);
871 memcpy(ctx->mcode + reloc->position, &mc, 4);
874 if (unlikely(offs < -0x2000000) || unlikely(offs >= 0x2000000))
876 memcpy(&mc, ctx->mcode + reloc->position, 4);
877 mc &= ~((0xffffU << 10) | 0x3ffU);
878 mc |= ((offs & 0xffffU) << 10) | ((offs & 0x3ff0000U) >> 16);
879 memcpy(ctx->mcode + reloc->position, &mc, 4);
882 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
887 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
889 if (unlikely(insn_writes_flags(insn))) {
890 if (unlikely(insn_opcode(insn) != INSN_FP_CMP_COND))
893 /*debug("insn: %08x", (unsigned)insn);*/
894 switch (insn_opcode(insn)) {
902 cgen_2ri16(LOONG_JIRL, R_ZERO, R_RA, 0);
904 case INSN_CALL_INDIRECT:
905 g(cgen_jmp_call_indirect(ctx, true));
908 g(cgen_mov(ctx, insn_op_size(insn), false));
911 g(cgen_mov(ctx, insn_op_size(insn), true));
913 case INSN_CMP_DEST_REG:
914 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
916 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
919 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
921 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
924 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
926 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
929 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
931 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
934 g(cgen_btx(ctx, insn_aux(insn)));
937 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
939 g(cgen_mov_mask(ctx, insn_aux(insn)));
941 case INSN_FP_CMP_COND:
942 g(cgen_fp_cmp_cond(ctx, insn_op_size(insn), insn_aux(insn)));
944 case INSN_FP_TEST_REG:
945 g(cgen_fp_test_reg(ctx));
948 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
951 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
953 case INSN_FP_TO_INT32:
954 case INSN_FP_TO_INT64:
955 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
957 case INSN_FP_FROM_INT32:
958 case INSN_FP_FROM_INT64:
959 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
965 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
967 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
970 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
972 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
974 case INSN_JMP_FP_TEST:
975 g(cgen_jmp_fp_test(ctx, insn_jump_size(insn)));
977 case INSN_JMP_INDIRECT:
978 g(cgen_jmp_call_indirect(ctx, false));
982 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);