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 RISCV_LB 0x00000003U
20 #define RISCV_LH 0x00001003U
21 #define RISCV_LW 0x00002003U
22 #define RISCV_LD 0x00003003U
23 #define RISCV_LBU 0x00004003U
24 #define RISCV_LHU 0x00005003U
25 #define RISCV_LWU 0x00006003U
26 #define RISCV_FL 0x00000007U
27 #define RISCV_FSL_H 0x00001000U
28 #define RISCV_FSL_W 0x00002000U
29 #define RISCV_FSL_D 0x00003000U
30 #define RISCV_FSL_Q 0x00004000U
31 #define RISCV_ADDI 0x00000013U
32 #define RISCV_BSETI 0x28001013U
33 #define RISCV_BCLRI 0x48001013U
34 #define RISCV_CLZ 0x60001013U
35 #define RISCV_BINVI 0x68001013U
36 #define RISCV_CTZ 0x60101013U
37 #define RISCV_CPOP 0x60201013U
38 #define RISCV_SEXT_B 0x60401013U
39 #define RISCV_SEXT_H 0x60501013U
40 #define RISCV_BEXTI 0x48005013U
41 #define RISCV_REV8 0x6b805013U
42 #define RISCV_SLLI 0x00001013U
43 #define RISCV_SLTI 0x00002013U
44 #define RISCV_SLTIU 0x00003013U
45 #define RISCV_XORI 0x00004013U
46 #define RISCV_SRLI 0x00005013U
47 #define RISCV_SRAI 0x40005013U
48 #define RISCV_RORI 0x60005013U
49 #define RISCV_ORI 0x00006013U
50 #define RISCV_ANDI 0x00007013U
51 #define RISCV_AUIPC 0x00000017U
52 #define RISCV_ADDIW 0x0000001bU
53 #define RISCV_SLLIW 0x0000101bU
54 #define RISCV_SRLIW 0x0000501bU
55 #define RISCV_SRAIW 0x4000501bU
56 #define RISCV_CLZW 0x6000101bU
57 #define RISCV_CTZW 0x6010101bU
58 #define RISCV_CPOPW 0x6020101bU
59 #define RISCV_RORIW 0x6000501bU
60 #define RISCV_SB 0x00000023U
61 #define RISCV_SH 0x00001023U
62 #define RISCV_SW 0x00002023U
63 #define RISCV_SD 0x00003023U
64 #define RISCV_FS 0x00000027U
65 #define RISCV_ADD 0x00000033U
66 #define RISCV_MUL 0x02000033U
67 #define RISCV_SUB 0x40000033U
68 #define RISCV_SLL 0x00001033U
69 #define RISCV_MULH 0x02001033U
70 #define RISCV_BSET 0x28001033U
71 #define RISCV_BCLR 0x48001033U
72 #define RISCV_BINV 0x68001033U
73 #define RISCV_ROL 0x60001033U
74 #define RISCV_SLT 0x00002033U
75 #define RISCV_SH1ADD 0x20002033U
76 #define RISCV_SLTU 0x00003033U
77 #define RISCV_XOR 0x00004033U
78 #define RISCV_DIV 0x02004033U
79 #define RISCV_SH2ADD 0x20004033U
80 #define RISCV_SRL 0x00005033U
81 #define RISCV_DIVU 0x02005033U
82 #define RISCV_SRA 0x40005033U
83 #define RISCV_BEXT 0x48005033U
84 #define RISCV_ROR 0x60005033U
85 #define RISCV_OR 0x00006033U
86 #define RISCV_REM 0x02006033U
87 #define RISCV_SH3ADD 0x20006033U
88 #define RISCV_AND 0x00007033U
89 #define RISCV_REMU 0x02007033U
90 #define RISCV_ANDN 0x40007033U
91 #define RISCV_LUI 0x00000037U
92 #define RISCV_ADDW 0x0000003bU
93 #define RISCV_ADD_UW 0x0800003bU
94 #define RISCV_SUBW 0x4000003bU
95 #define RISCV_SLLW 0x0000103bU
96 #define RISCV_MULW 0x0200003bU
97 #define RISCV_ROLW 0x6000103bU
98 #define RISCV_DIVW 0x0200403bU
99 #define RISCV_ZEXT_H 0x0800403bU
100 #define RISCV_SRLW 0x0000503bU
101 #define RISCV_DIVUW 0x0200503bU
102 #define RISCV_SRAW 0x4000503bU
103 #define RISCV_RORW 0x6000503bU
104 #define RISCV_REMW 0x0200603bU
105 #define RISCV_REMUW 0x0200703bU
106 #define RISCV_FADD 0x00000053U
107 #define RISCV_FSUB 0x08000053U
108 #define RISCV_FMUL 0x10000053U
109 #define RISCV_FDIV 0x18000053U
110 #define RISCV_FSGNJ 0x20000053U
111 #define RISCV_FLE 0xa0000053U
112 #define RISCV_FCVT_TO_W 0xc0000053U
113 #define RISCV_FCVT_TO_L 0xc0200053U
114 #define RISCV_FCVT_FROM_W 0xd0000053U
115 #define RISCV_FCVT_FROM_L 0xd0200053U
116 #define RISCV_FSGNJN 0x20001053U
117 #define RISCV_FLT 0xa0001053U
118 #define RISCV_FSGNJX 0x20002053U
119 #define RISCV_FEQ 0xa0002053U
120 #define RISCV_FSQRT 0x58000053U
121 #define RISCV_F_RNE 0x00000000U
122 #define RISCV_F_RTZ 0x00001000U
123 #define RISCV_F_RDN 0x00002000U
124 #define RISCV_F_RUP 0x00003000U
125 #define RISCV_F_RMM 0x00004000U
126 #define RISCV_F_DYN 0x00007000U
127 #define RISCV_F_SINGLE 0x00000000U
128 #define RISCV_F_DOUBLE 0x02000000U
129 #define RISCV_F_HALF 0x04000000U
130 #define RISCV_F_QUAD 0x06000000U
131 #define RISCV_BEQ 0x00000063U
132 #define RISCV_BNE 0x00001063U
133 #define RISCV_BLT 0x00004063U
134 #define RISCV_BGE 0x00005063U
135 #define RISCV_BLTU 0x00006063U
136 #define RISCV_BGEU 0x00007063U
137 #define RISCV_JALR 0x00000067U
138 #define RISCV_JAL 0x0000006fU
140 #define RISCV_C_J 0xa001U
141 #define RISCV_C_BEQZ 0xc001U
142 #define RISCV_C_BNEZ 0xe001U
144 static bool cgen_rv_compress(struct codegen_context *ctx, uint32_t insn)
146 if (likely(cpu_test_feature(CPU_FEATURE_c))) {
149 binary_search(size_t, n_array_elements(riscv_compress), result, riscv_compress[result].l == insn, riscv_compress[result].l < insn, goto uncompressed);
150 c = riscv_compress[result].s;
159 #define cgen_rv(dword) \
161 if (unlikely(!cgen_rv_compress(ctx, dword))) \
166 static bool attr_w cgen_memory_load(struct codegen_context *ctx, uint32_t mc, unsigned rd, unsigned rs, int64_t imm)
168 if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
169 internal(file_line, "cgen_memory_load: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
170 mc |= (uint32_t)rs << 15;
171 mc |= (uint32_t)rd << 7;
172 mc |= (uint32_t)imm << 20;
177 static bool attr_w cgen_memory_store(struct codegen_context *ctx, uint32_t mc, unsigned rs1, unsigned rs2, int64_t imm)
179 if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
180 internal(file_line, "cgen_memory_store: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
181 mc |= (uint32_t)rs1 << 15;
182 mc |= (uint32_t)rs2 << 20;
183 mc |= ((uint32_t)imm & 0x1f) << 7;
184 mc |= ((uint32_t)imm & 0xfe0) << 20;
189 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, bool call)
191 uint8_t reg = cget_one(ctx);
195 mc |= (uint32_t)R_RA << 7;
196 mc |= (uint32_t)reg << 15;
201 static uint32_t riscv_fp_op_size(unsigned fp_op_size)
203 switch (fp_op_size) {
204 case OP_SIZE_2: return RISCV_F_HALF;
205 case OP_SIZE_4: return RISCV_F_SINGLE;
206 case OP_SIZE_8: return RISCV_F_DOUBLE;
207 case OP_SIZE_16: return RISCV_F_QUAD;
208 default: internal(file_line, "riscv_fp_op_size: invalid size %u", fp_op_size);
213 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
218 uint8_t *arg1 = ctx->code_position;
219 uint8_t *arg2 = arg1 + arg_size(*arg1);
220 ctx->code_position = arg2 + arg_size(*arg2);
221 if (arg1[0] < 0x20) {
222 if (arg2[0] == ARG_IMM) {
223 imm = get_imm(&arg2[1]);
224 if (unlikely((imm & 0xfff) != 0) ||
225 unlikely(imm < -0x80000000LL) ||
226 unlikely(imm >= 0x80000000LL))
227 internal(file_line, "cgen_mov: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
229 mc |= (uint32_t)arg1[0] << 7;
234 if (arg2[0] == ARG_ADDRESS_1) {
235 imm = get_imm(&arg2[2]);
237 case OP_SIZE_1: mc = RISCV_LBU; break;
238 case OP_SIZE_2: mc = RISCV_LHU; break;
239 case OP_SIZE_4: mc = RISCV_LWU; break;
240 case OP_SIZE_8: mc = RISCV_LD; break;
241 default: goto invalid;
243 g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], imm));
246 if (arg2[0] < 0x20) {
248 case OP_SIZE_1: mc = RISCV_ANDI | ((uint32_t)0xff << 20); break;
249 case OP_SIZE_2: mc = RISCV_ZEXT_H; break;
250 case OP_SIZE_4: mc = RISCV_ADD_UW; break;
251 case OP_SIZE_8: mc = RISCV_ADDI; break;
252 default: goto invalid;
254 mc |= (uint32_t)arg1[0] << 7;
255 mc |= (uint32_t)arg2[0] << 15;
261 if (reg_is_fp(arg1[0])) {
262 if (reg_is_fp(arg2[0])) {
264 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
265 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
266 mc |= (uint32_t)(arg2[0] & 0x1f) << 20;
267 mc |= riscv_fp_op_size(size);
271 if (arg2[0] == ARG_ADDRESS_1) {
272 imm = get_imm(&arg2[2]);
274 case OP_SIZE_2: mc = RISCV_FL | RISCV_FSL_H; break;
275 case OP_SIZE_4: mc = RISCV_FL | RISCV_FSL_W; break;
276 case OP_SIZE_8: mc = RISCV_FL | RISCV_FSL_D; break;
277 case OP_SIZE_16:mc = RISCV_FL | RISCV_FSL_Q; break;
278 default: goto invalid;
280 g(cgen_memory_load(ctx, mc, arg1[0] & 0x1f, arg2[1], imm));
285 if (arg1[0] == ARG_ADDRESS_1) {
286 if (arg2[0] == ARG_IMM) {
287 imm = get_imm(&arg2[1]);
288 if (unlikely(imm != 0))
292 if (arg2[0] < 0x20) {
293 imm = get_imm(&arg1[2]);
295 case OP_SIZE_1: mc = RISCV_SB; break;
296 case OP_SIZE_2: mc = RISCV_SH; break;
297 case OP_SIZE_4: mc = RISCV_SW; break;
298 case OP_SIZE_8: mc = RISCV_SD; break;
299 default: goto invalid;
301 g(cgen_memory_store(ctx, mc, arg1[1], arg2[0], imm));
304 if (reg_is_fp(arg2[0])) {
305 imm = get_imm(&arg1[2]);
307 case OP_SIZE_2: mc = RISCV_FS | RISCV_FSL_H; break;
308 case OP_SIZE_4: mc = RISCV_FS | RISCV_FSL_W; break;
309 case OP_SIZE_8: mc = RISCV_FS | RISCV_FSL_D; break;
310 case OP_SIZE_16:mc = RISCV_FS | RISCV_FSL_Q; break;
311 default: goto invalid;
313 g(cgen_memory_store(ctx, mc, arg1[1], arg2[0] & 0x1f, imm));
320 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
324 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
326 uint8_t *arg1, *arg2;
327 if (size == OP_SIZE_NATIVE) {
328 g(cgen_mov(ctx, size));
331 arg1 = ctx->code_position;
332 arg2 = arg1 + arg_size(*arg1);
333 ctx->code_position = arg2 + arg_size(*arg2);
335 if (unlikely(arg1[0] >= 0x20))
338 if (arg2[0] == ARG_ADDRESS_1) {
341 case OP_SIZE_1: mc = RISCV_LB; break;
342 case OP_SIZE_2: mc = RISCV_LH; break;
343 case OP_SIZE_4: mc = RISCV_LW; break;
344 default: goto invalid;
346 g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], get_imm(&arg2[2])));
350 if (arg2[0] < 0x20) {
353 case OP_SIZE_1: mc = RISCV_SEXT_B; break;
354 case OP_SIZE_2: mc = RISCV_SEXT_H; break;
355 case OP_SIZE_4: mc = RISCV_ADDIW; break;
356 default: goto invalid;
358 mc |= (uint32_t)arg1[0] << 7;
359 mc |= (uint32_t)arg2[0] << 15;
365 internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, arg1[0], arg2[0]);
369 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
374 uint8_t *arg1 = ctx->code_position;
375 uint8_t *arg2 = arg1 + arg_size(*arg1);
376 uint8_t *arg3 = arg2 + arg_size(*arg2);
377 ctx->code_position = arg3 + arg_size(*arg3);
378 if (arg3[0] == ARG_IMM) {
379 int64_t imm = get_imm(&arg3[1]);
380 if (unlikely(imm < -0x800) && unlikely(imm >= 0x800))
381 internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
383 case COND_B: mc = RISCV_SLTIU; break;
384 case COND_L: mc = RISCV_SLTI; break;
385 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
387 mc |= (uint32_t)arg1[0] << 7;
388 mc |= (uint32_t)arg2[0] << 15;
389 mc |= (uint32_t)imm << 20;
393 if (arg2[0] == ARG_IMM) {
394 int64_t imm = get_imm(&arg2[1]);
395 if (unlikely(imm != 0))
396 internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
400 case COND_B: mc = RISCV_SLTU; break;
401 case COND_A: mc = RISCV_SLTU; swap = true; break;
402 case COND_L: mc = RISCV_SLT; break;
403 case COND_G: mc = RISCV_SLT; swap = true; break;
404 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
407 uint8_t *argx = arg2;
411 mc |= (uint32_t)arg1[0] << 7;
412 mc |= (uint32_t)arg2[0] << 15;
413 mc |= (uint32_t)arg3[0] << 20;
418 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
421 uint8_t *arg1 = ctx->code_position;
422 uint8_t *arg2 = arg1 + arg_size(*arg1);
423 uint8_t *arg3 = arg2 + arg_size(*arg2);
424 ctx->code_position = arg3 + arg_size(*arg3);
426 if (arg3[0] == ARG_IMM) {
427 int64_t imm = get_imm(&arg3[1]);
428 if (alu == ALU_SUB) {
429 imm = -(uint64_t)imm;
432 if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
433 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
435 case ALU_ADD: mc = size == OP_SIZE_8 ? RISCV_ADDI : RISCV_ADDIW; break;
436 case ALU_XOR: mc = RISCV_XORI; break;
437 case ALU_OR: mc = RISCV_ORI; break;
438 case ALU_AND: mc = RISCV_ANDI; break;
439 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
441 mc |= (uint32_t)arg1[0] << 7;
442 mc |= (uint32_t)arg2[0] << 15;
443 mc |= (uint32_t)imm << 20;
447 if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
448 uint8_t *arg_swp = arg3;
452 if (arg2[0] == ARG_SHIFTED_REGISTER) {
453 if (unlikely(alu != ALU_ADD) || unlikely(size != OP_SIZE_8))
454 internal(file_line, "cgen_alu: invalid shifted alu %u, %u", alu, size);
455 if (arg2[1] == (ARG_SHIFT_LSL | 0))
457 else if (arg2[1] == (ARG_SHIFT_LSL | 1))
459 else if (arg2[1] == (ARG_SHIFT_LSL | 2))
461 else if (arg2[1] == (ARG_SHIFT_LSL | 3))
464 internal(file_line, "cgen_alu: invalid shifted register operation: %02x", arg2[1]);
465 mc |= (uint32_t)arg1[0] << 7;
466 mc |= (uint32_t)arg2[2] << 15;
467 mc |= (uint32_t)arg3[0] << 20;
472 case ALU_ADD: mc = size == OP_SIZE_8 ? RISCV_ADD : RISCV_ADDW; break;
473 case ALU_SUB: mc = size == OP_SIZE_8 ? RISCV_SUB : RISCV_SUBW; break;
474 case ALU_XOR: mc = RISCV_XOR; break;
475 case ALU_OR: mc = RISCV_OR; break;
476 case ALU_AND: mc = RISCV_AND; break;
477 case ALU_ANDN: mc = RISCV_ANDN; break;
478 case ALU_MUL: mc = size == OP_SIZE_8 ? RISCV_MUL : RISCV_MULW; break;
479 case ALU_SMULH: if (unlikely(size != OP_SIZE_8))
481 mc = RISCV_MULH; break;
482 case ALU_UDIV: mc = size == OP_SIZE_8 ? RISCV_DIVU : RISCV_DIVUW; break;
483 case ALU_SDIV: mc = size == OP_SIZE_8 ? RISCV_DIV : RISCV_DIVW; break;
484 case ALU_UREM: mc = size == OP_SIZE_8 ? RISCV_REMU : RISCV_REMUW; break;
485 case ALU_SREM: mc = size == OP_SIZE_8 ? RISCV_REM : RISCV_REMW; break;
487 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
489 mc |= (uint32_t)arg1[0] << 7;
490 mc |= (uint32_t)arg2[0] << 15;
491 mc |= (uint32_t)arg3[0] << 20;
496 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
500 uint8_t *arg1 = ctx->code_position;
501 uint8_t *arg2 = arg1 + arg_size(*arg1);
502 ctx->code_position = arg2 + arg_size(*arg2);
504 case ALU1_NOT: mc = RISCV_XORI | ((uint32_t)-1 << 20); break;
505 case ALU1_NEG: mc = (size == OP_SIZE_8 ? RISCV_SUB : RISCV_SUBW); tgt20 = true; break;
506 case ALU1_INC: mc = (size == OP_SIZE_8 ? RISCV_ADDI : RISCV_ADDIW) | ((uint32_t)1 << 20); break;
507 case ALU1_DEC: mc = (size == OP_SIZE_8 ? RISCV_ADDI : RISCV_ADDIW) | ((uint32_t)-1 << 20); break;
508 case ALU1_BSWAP:if (unlikely(size != OP_SIZE_8))
510 mc = RISCV_REV8; break;
511 case ALU1_BSF: mc = size == OP_SIZE_8 ? RISCV_CTZ : RISCV_CTZW; break;
512 case ALU1_LZCNT:mc = size == OP_SIZE_8 ? RISCV_CLZ : RISCV_CLZW; break;
513 case ALU1_POPCNT:mc = size == OP_SIZE_8 ? RISCV_CPOP : RISCV_CPOPW; break;
515 default: internal(file_line, "cgen_alu1: invalid alu %u", alu);
518 mc |= (uint32_t)arg1[0] << 7;
519 mc |= (uint32_t)arg2[0] << (tgt20 ? 20 : 15);
524 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
527 uint8_t *arg1 = ctx->code_position;
528 uint8_t *arg2 = arg1 + arg_size(*arg1);
529 uint8_t *arg3 = arg2 + arg_size(*arg2);
530 ctx->code_position = arg3 + arg_size(*arg3);
531 if (arg3[0] == ARG_IMM) {
532 int64_t imm = get_imm(&arg3[1]);
534 imm = -(uint64_t)imm;
535 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
537 case ROT_ROL: mc = size == OP_SIZE_4 ? RISCV_RORIW : RISCV_RORI; break;
538 case ROT_ROR: mc = size == OP_SIZE_4 ? RISCV_RORIW : RISCV_RORI; break;
539 case ROT_SHL: mc = size == OP_SIZE_4 ? RISCV_SLLIW : RISCV_SLLI; break;
540 case ROT_SHR: mc = size == OP_SIZE_4 ? RISCV_SRLIW : RISCV_SRLI; break;
541 case ROT_SAR: mc = size == OP_SIZE_4 ? RISCV_SRAIW : RISCV_SRAI; break;
542 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
544 mc |= (uint32_t)arg1[0] << 7;
545 mc |= (uint32_t)arg2[0] << 15;
546 mc |= (uint32_t)imm << 20;
551 case ROT_ROL: mc = size == OP_SIZE_4 ? RISCV_ROLW : RISCV_ROL; break;
552 case ROT_ROR: mc = size == OP_SIZE_4 ? RISCV_RORW : RISCV_ROR; break;
553 case ROT_SHL: mc = size == OP_SIZE_4 ? RISCV_SLLW : RISCV_SLL; break;
554 case ROT_SHR: mc = size == OP_SIZE_4 ? RISCV_SRLW : RISCV_SRL; break;
555 case ROT_SAR: mc = size == OP_SIZE_4 ? RISCV_SRAW : RISCV_SRA; break;
556 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
558 mc |= (uint32_t)arg1[0] << 7;
559 mc |= (uint32_t)arg2[0] << 15;
560 mc |= (uint32_t)arg3[0] << 20;
565 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
568 uint8_t *arg1 = ctx->code_position;
569 uint8_t *arg2 = arg1 + arg_size(*arg1);
570 uint8_t *arg3 = arg2 + arg_size(*arg2);
571 ctx->code_position = arg3 + arg_size(*arg3);
572 if (arg3[0] == ARG_IMM) {
573 int64_t imm = get_imm(&arg3[1]) & 0x3f;
575 case BTX_BTS: mc = RISCV_BSETI; break;
576 case BTX_BTR: mc = RISCV_BCLRI; break;
577 case BTX_BTC: mc = RISCV_BINVI; break;
578 case BTX_BTEXT: mc = RISCV_BEXTI; break;
579 default: internal(file_line, "cgen_btx: invalid alu %u", alu);
581 mc |= (uint32_t)arg1[0] << 7;
582 mc |= (uint32_t)arg2[0] << 15;
583 mc |= (uint32_t)imm << 20;
588 case BTX_BTS: mc = RISCV_BSET; break;
589 case BTX_BTR: mc = RISCV_BCLR; break;
590 case BTX_BTC: mc = RISCV_BINV; break;
591 case BTX_BTEXT: mc = RISCV_BEXT; break;
592 default: internal(file_line, "cgen_btx: invalid alu %u", alu);
594 mc |= (uint32_t)arg1[0] << 7;
595 mc |= (uint32_t)arg2[0] << 15;
596 mc |= (uint32_t)arg3[0] << 20;
601 static bool attr_w cgen_fp_cmp_dest_reg(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 uint8_t *arg3 = arg2 + arg_size(*arg2);
608 ctx->code_position = arg3 + arg_size(*arg3);
610 case FP_COND_E: mc = RISCV_FEQ; break;
611 case FP_COND_A: mc = RISCV_FLT; swap = true; break;
612 case FP_COND_BE: mc = RISCV_FLE; break;
613 case FP_COND_B: mc = RISCV_FLT; break;
614 case FP_COND_AE: mc = RISCV_FLE; swap = true; break;
615 default: internal(file_line, "cgen_fp_cmp_dest_reg: invalid condition %u", aux);
618 uint8_t *argx = arg2;
623 case OP_SIZE_2: mc |= RISCV_F_HALF; break;
624 case OP_SIZE_4: mc |= RISCV_F_SINGLE; break;
625 case OP_SIZE_8: mc |= RISCV_F_DOUBLE; break;
626 case OP_SIZE_16: mc |= RISCV_F_QUAD; break;
627 default: internal(file_line, "cgen_fp_cmp_dest_reg: invalid size %u", op_size);
629 mc |= (uint32_t)arg1[0] << 7;
630 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
631 mc |= (uint32_t)(arg3[0] & 0x1f) << 20;
636 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
639 uint8_t *arg1 = ctx->code_position;
640 uint8_t *arg2 = arg1 + arg_size(*arg1);
641 uint8_t *arg3 = arg2 + arg_size(*arg2);
642 ctx->code_position = arg3 + arg_size(*arg3);
644 case FP_ALU_ADD: mc = RISCV_FADD; break;
645 case FP_ALU_SUB: mc = RISCV_FSUB; break;
646 case FP_ALU_MUL: mc = RISCV_FMUL; break;
647 case FP_ALU_DIV: mc = RISCV_FDIV; break;
648 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
651 mc |= riscv_fp_op_size(op_size);
652 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
653 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
654 mc |= (uint32_t)(arg3[0] & 0x1f) << 20;
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 = RISCV_FSGNJN;
667 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
668 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
669 mc |= (uint32_t)(arg2[0] & 0x1f) << 20;
671 case FP_ALU1_SQRT: mc = RISCV_FSQRT;
672 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
673 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
676 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
678 mc |= riscv_fp_op_size(op_size);
683 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
686 uint8_t *arg1 = ctx->code_position;
687 uint8_t *arg2 = arg1 + arg_size(*arg1);
688 ctx->code_position = arg2 + arg_size(*arg2);
689 switch (int_op_size) {
690 case OP_SIZE_4: mc = RISCV_FCVT_TO_W; break;
691 case OP_SIZE_8: mc = RISCV_FCVT_TO_L; break;
692 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
695 mc |= riscv_fp_op_size(fp_op_size);
696 mc |= (uint32_t)arg1[0] << 7;
697 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
702 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
705 uint8_t *arg1 = ctx->code_position;
706 uint8_t *arg2 = arg1 + arg_size(*arg1);
707 ctx->code_position = arg2 + arg_size(*arg2);
708 switch (int_op_size) {
709 case OP_SIZE_4: mc = RISCV_FCVT_FROM_W; break;
710 case OP_SIZE_8: mc = RISCV_FCVT_FROM_L; break;
711 default: internal(file_line, "cgen_fp_from_int: invalid int size %u", int_op_size);
714 mc |= riscv_fp_op_size(fp_op_size);
715 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
716 mc |= (uint32_t)arg2[0] << 15;
721 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
723 if (length == JMP_SHORTEST && likely(cpu_test_feature(CPU_FEATURE_c))) {
724 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
726 } else if (length <= JMP_LONG) {
727 g(add_relocation(ctx, JMP_LONG, 0, NULL));
728 cgen_four(RISCV_JAL);
729 } else if (length == JMP_EXTRA_LONG) {
730 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
731 cgen_four(RISCV_AUIPC | ((uint32_t)R_CONST_HELPER << 7));
732 cgen_four(RISCV_JALR | ((uint32_t)R_CONST_HELPER << 15));
734 internal(file_line, "cgen_jmp: invalid length %u", length);
739 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
743 if (length > JMP_SHORT)
746 case COND_B: mc = RISCV_BLTU; break;
747 case COND_AE: mc = RISCV_BGEU; break;
748 case COND_E: mc = RISCV_BEQ; break;
749 case COND_NE: mc = RISCV_BNE; break;
750 case COND_BE: mc = RISCV_BGEU; swap = true; break;
751 case COND_A: mc = RISCV_BLTU; swap = true; break;
753 case COND_L: mc = RISCV_BLT; break;
755 case COND_GE: mc = RISCV_BGE; break;
756 case COND_LE: mc = RISCV_BGE; swap = true; break;
757 case COND_G: mc = RISCV_BLT; swap = true; break;
758 default: goto invalid;
761 unsigned regx = reg1;
766 mc |= (uint32_t)reg1 << 15;
767 mc |= (uint32_t)reg2 << 20;
769 if (length == JMP_SHORTEST && (cond == COND_E || cond == COND_NE) && (reg1 & 0x18) == 0x8 && reg2 == R_ZERO && cpu_test_feature(CPU_FEATURE_c)) {
770 uint16_t mc2 = cond == COND_E ? RISCV_C_BEQZ : RISCV_C_BNEZ;
771 mc2 |= ((uint16_t)reg1 & 0x7) << 7;
772 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
774 } else if (length <= JMP_SHORT) {
775 g(add_relocation(ctx, JMP_SHORT, reloc_offset, NULL));
777 } else if (length == JMP_LONG) {
780 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
783 } else if (length == JMP_EXTRA_LONG) {
786 g(add_relocation(ctx, JMP_EXTRA_LONG, reloc_offset, NULL));
787 cgen_four(RISCV_AUIPC | ((uint32_t)R_CONST_HELPER << 7));
788 cgen_four(RISCV_JALR | ((uint32_t)R_CONST_HELPER << 15));
790 internal(file_line, "cgen_jmp_12regs: invalid length %u", length);
795 internal(file_line, "cgen_jmp_12regs: invalid arguments %u, %02x, %02x", cond, reg1, reg2);
799 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
801 uint8_t *arg1 = ctx->code_position;
802 ctx->code_position = arg1 + arg_size(*arg1);
803 if (arg1[0] < 0x20) {
804 return cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1);
806 internal(file_line, "cgen_jmp_reg: invalid argument %02x", arg1[0]);
810 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
812 uint8_t *arg1 = ctx->code_position;
813 uint8_t *arg2 = arg1 + arg_size(*arg1);
814 ctx->code_position = arg2 + arg_size(*arg2);
815 if (arg1[0] < 0x20 && arg2[0] < 0x20) {
816 return cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2);
818 internal(file_line, "cgen_jmp_2regs: invalid arguments %02x, %02x", arg1[0], arg2[0]);
823 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
828 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 1) - (int64_t)(reloc->position >> 1);
829 switch (reloc->length) {
831 memcpy(&mc2, ctx->mcode + reloc->position, 2);
832 if ((mc2 & 0xe003) == RISCV_C_J) {
833 if (unlikely(offs < -0x400) || unlikely(offs >= 0x400))
836 mc2 |= ((uint32_t)offs & 0x7) << 3;
837 mc2 |= ((uint32_t)offs & 0x8) << 8;
838 mc2 |= ((uint32_t)offs & 0x10) >> 2;
839 mc2 |= ((uint32_t)offs & 0x20) << 2;
840 mc2 |= ((uint32_t)offs & 0x40);
841 mc2 |= ((uint32_t)offs & 0x180) << 2;
842 mc2 |= ((uint32_t)offs & 0x200) >> 1;
843 mc2 |= ((uint32_t)offs & 0x400) << 2;
844 } else if ((mc2 & 0xe003) == RISCV_C_BEQZ || (mc2 & 0xe003) == RISCV_C_BNEZ) {
845 if (unlikely(offs < -0x80) || unlikely(offs >= 0x80))
848 mc2 |= ((uint32_t)offs & 0x3) << 3;
849 mc2 |= ((uint32_t)offs & 0xc) << 8;
850 mc2 |= ((uint32_t)offs & 0x10) >> 2;
851 mc2 |= ((uint32_t)offs & 0x60);
852 mc2 |= ((uint32_t)offs & 0x80) << 5;
854 internal(file_line, "resolve_relocation: invalid 2-byte instruction %04x", mc2);
856 memcpy(ctx->mcode + reloc->position, &mc2, 2);
859 if (unlikely(offs < -0x800) || unlikely(offs >= 0x800))
861 memcpy(&mc, ctx->mcode + reloc->position, 4);
863 mc |= ((uint32_t)offs & 0xf) << (8 - 0);
864 mc |= ((uint32_t)offs & 0x3f0) << (25 - 4);
865 mc |= ((uint32_t)offs & 0x400) >> (10 - 7);
866 mc |= ((uint32_t)offs & 0x800) << (31 - 11);
867 memcpy(ctx->mcode + reloc->position, &mc, 4);
870 if (unlikely(offs < -0x80000) || unlikely(offs >= 0x80000))
872 memcpy(&mc, ctx->mcode + reloc->position, 4);
874 mc |= ((uint32_t)offs & 0x3ff) << (21 - 0);
875 mc |= ((uint32_t)offs & 0x400) << (20 - 10);
876 mc |= ((uint32_t)offs & 0x7f800) << (12 - 11);
877 mc |= ((uint32_t)offs & 0x80000) << (31 - 19);
878 memcpy(ctx->mcode + reloc->position, &mc, 4);
881 offs = (uint64_t)offs << 1;
882 memcpy(&mc8, ctx->mcode + reloc->position, 8);
883 mc8 &= 0x000fffff00000fffULL;
884 mc8 |= ((uint64_t)offs & 0xfffULL) << (32 + 20);
886 offs = (uint64_t)offs + 0x1000;
888 if (unlikely(offs < -0x80000000LL) || unlikely(offs >= 0x80000000LL))
890 mc8 |= ((uint64_t)offs & 0xfffff000ULL);
891 memcpy(ctx->mcode + reloc->position, &mc8, 8);
894 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
899 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
901 if (unlikely(insn_writes_flags(insn)))
903 /*debug("insn: %08x", (unsigned)insn);*/
904 switch (insn_opcode(insn)) {
912 cgen_rv(RISCV_JALR | ((uint32_t)R_RA << 15));
914 case INSN_CALL_INDIRECT:
915 g(cgen_jmp_call_indirect(ctx, true));
918 g(cgen_mov(ctx, insn_op_size(insn)));
921 g(cgen_movsx(ctx, insn_op_size(insn)));
923 case INSN_CMP_DEST_REG:
924 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
926 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
929 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
931 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
934 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
936 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
939 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
941 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
944 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
946 g(cgen_btx(ctx, insn_aux(insn)));
948 case INSN_FP_CMP_DEST_REG:
949 g(cgen_fp_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
952 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
955 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
957 case INSN_FP_TO_INT32:
958 case INSN_FP_TO_INT64:
959 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
961 case INSN_FP_FROM_INT32:
962 case INSN_FP_FROM_INT64:
963 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
966 g(cgen_jmp(ctx, insn_jump_size(insn)));
969 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
971 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
974 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
976 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
978 case INSN_JMP_INDIRECT:
979 g(cgen_jmp_call_indirect(ctx, false));
983 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);