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 bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
206 uint8_t *arg1 = ctx->code_position;
207 uint8_t *arg2 = arg1 + arg_size(*arg1);
208 ctx->code_position = arg2 + arg_size(*arg2);
209 if (arg1[0] < 0x20) {
210 if (arg2[0] == ARG_IMM) {
211 imm = get_imm(&arg2[1]);
212 if (unlikely((imm & 0xfff) != 0) ||
213 unlikely(imm < -0x80000000LL) ||
214 unlikely(imm >= 0x80000000LL))
215 internal(file_line, "cgen_mov: invalid immediate value %"PRIxMAX"", (uintmax_t)imm);
217 mc |= (uint32_t)arg1[0] << 7;
222 if (arg2[0] == ARG_ADDRESS_1) {
223 imm = get_imm(&arg2[2]);
225 case OP_SIZE_1: mc = RISCV_LBU; break;
226 case OP_SIZE_2: mc = RISCV_LHU; break;
227 case OP_SIZE_4: mc = RISCV_LWU; break;
228 case OP_SIZE_8: mc = RISCV_LD; break;
229 default: goto invalid;
231 g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], imm));
234 if (arg2[0] < 0x20) {
236 case OP_SIZE_1: mc = RISCV_ANDI | ((uint32_t)0xff << 20); break;
237 case OP_SIZE_2: mc = RISCV_ZEXT_H; break;
238 case OP_SIZE_4: mc = RISCV_ADD_UW; break;
239 case OP_SIZE_8: mc = RISCV_ADDI; break;
240 default: goto invalid;
242 mc |= (uint32_t)arg1[0] << 7;
243 mc |= (uint32_t)arg2[0] << 15;
249 if (arg1[0] < 0x40) {
250 if (arg2[0] == ARG_ADDRESS_1) {
251 imm = get_imm(&arg2[2]);
253 case OP_SIZE_2: mc = RISCV_FL | RISCV_FSL_H; break;
254 case OP_SIZE_4: mc = RISCV_FL | RISCV_FSL_W; break;
255 case OP_SIZE_8: mc = RISCV_FL | RISCV_FSL_D; break;
256 case OP_SIZE_16:mc = RISCV_FL | RISCV_FSL_Q; break;
257 default: goto invalid;
259 g(cgen_memory_load(ctx, mc, arg1[0] & 0x1f, arg2[1], imm));
264 if (arg1[0] == ARG_ADDRESS_1) {
265 if (arg2[0] == ARG_IMM) {
266 imm = get_imm(&arg2[1]);
267 if (unlikely(imm != 0))
271 if (arg2[0] < 0x20) {
272 imm = get_imm(&arg1[2]);
274 case OP_SIZE_1: mc = RISCV_SB; break;
275 case OP_SIZE_2: mc = RISCV_SH; break;
276 case OP_SIZE_4: mc = RISCV_SW; break;
277 case OP_SIZE_8: mc = RISCV_SD; break;
278 default: goto invalid;
280 g(cgen_memory_store(ctx, mc, arg1[1], arg2[0], imm));
283 if (arg2[0] < 0x40) {
284 imm = get_imm(&arg1[2]);
286 case OP_SIZE_2: mc = RISCV_FS | RISCV_FSL_H; break;
287 case OP_SIZE_4: mc = RISCV_FS | RISCV_FSL_W; break;
288 case OP_SIZE_8: mc = RISCV_FS | RISCV_FSL_D; break;
289 case OP_SIZE_16:mc = RISCV_FS | RISCV_FSL_Q; break;
290 default: goto invalid;
292 g(cgen_memory_store(ctx, mc, arg1[1], arg2[0] & 0x1f, imm));
299 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
303 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
305 uint8_t *arg1, *arg2;
306 if (size == OP_SIZE_NATIVE) {
307 g(cgen_mov(ctx, size));
310 arg1 = ctx->code_position;
311 arg2 = arg1 + arg_size(*arg1);
312 ctx->code_position = arg2 + arg_size(*arg2);
314 if (unlikely(arg1[0] >= 0x20))
317 if (arg2[0] == ARG_ADDRESS_1) {
320 case OP_SIZE_1: mc = RISCV_LB; break;
321 case OP_SIZE_2: mc = RISCV_LH; break;
322 case OP_SIZE_4: mc = RISCV_LW; break;
323 default: goto invalid;
325 g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], get_imm(&arg2[2])));
329 if (arg2[0] < 0x20) {
332 case OP_SIZE_1: mc = RISCV_SEXT_B; break;
333 case OP_SIZE_2: mc = RISCV_SEXT_H; break;
334 case OP_SIZE_4: mc = RISCV_ADDIW; break;
335 default: goto invalid;
337 mc |= (uint32_t)arg1[0] << 7;
338 mc |= (uint32_t)arg2[0] << 15;
344 internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, arg1[0], arg2[0]);
348 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
353 uint8_t *arg1 = ctx->code_position;
354 uint8_t *arg2 = arg1 + arg_size(*arg1);
355 uint8_t *arg3 = arg2 + arg_size(*arg2);
356 ctx->code_position = arg3 + arg_size(*arg3);
357 if (arg3[0] == ARG_IMM) {
358 int64_t imm = get_imm(&arg3[1]);
359 if (unlikely(imm < -0x800) && unlikely(imm >= 0x800))
360 internal(file_line, "cgen_cmp_dest_reg: invalid imm value %"PRIxMAX"", (intmax_t)imm);
362 case COND_B: mc = RISCV_SLTIU; break;
363 case COND_L: mc = RISCV_SLTI; break;
364 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
366 mc |= (uint32_t)arg1[0] << 7;
367 mc |= (uint32_t)arg2[0] << 15;
368 mc |= (uint32_t)imm << 20;
372 if (arg2[0] == ARG_IMM) {
373 int64_t imm = get_imm(&arg2[1]);
374 if (unlikely(imm != 0))
375 internal(file_line, "cgen_cmp_dest_reg: non-zero second argument");
379 case COND_B: mc = RISCV_SLTU; break;
380 case COND_A: mc = RISCV_SLTU; swap = true; break;
381 case COND_L: mc = RISCV_SLT; break;
382 case COND_G: mc = RISCV_SLT; swap = true; break;
383 default: internal(file_line, "cgen_cmp_dest_reg: invalid condition %u", aux);
386 uint8_t *argx = arg2;
390 mc |= (uint32_t)arg1[0] << 7;
391 mc |= (uint32_t)arg2[0] << 15;
392 mc |= (uint32_t)arg3[0] << 20;
397 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
400 uint8_t *arg1 = ctx->code_position;
401 uint8_t *arg2 = arg1 + arg_size(*arg1);
402 uint8_t *arg3 = arg2 + arg_size(*arg2);
403 ctx->code_position = arg3 + arg_size(*arg3);
405 if (arg3[0] == ARG_IMM) {
406 int64_t imm = get_imm(&arg3[1]);
407 if (alu == ALU_SUB) {
408 imm = -(uint64_t)imm;
411 if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
412 internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
414 case ALU_ADD: mc = size == OP_SIZE_8 ? RISCV_ADDI : RISCV_ADDIW; break;
415 case ALU_XOR: mc = RISCV_XORI; break;
416 case ALU_OR: mc = RISCV_ORI; break;
417 case ALU_AND: mc = RISCV_ANDI; break;
418 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
420 mc |= (uint32_t)arg1[0] << 7;
421 mc |= (uint32_t)arg2[0] << 15;
422 mc |= (uint32_t)imm << 20;
426 if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
427 uint8_t *arg_swp = arg3;
431 if (arg2[0] == ARG_SHIFTED_REGISTER) {
432 if (unlikely(alu != ALU_ADD) || unlikely(size != OP_SIZE_8))
433 internal(file_line, "cgen_alu: invalid shifted alu %u, %u", alu, size);
434 if (arg2[1] == (ARG_SHIFT_LSL | 0))
436 else if (arg2[1] == (ARG_SHIFT_LSL | 1))
438 else if (arg2[1] == (ARG_SHIFT_LSL | 2))
440 else if (arg2[1] == (ARG_SHIFT_LSL | 3))
443 internal(file_line, "cgen_alu: invalid shifted register operation: %02x", arg2[1]);
444 mc |= (uint32_t)arg1[0] << 7;
445 mc |= (uint32_t)arg2[2] << 15;
446 mc |= (uint32_t)arg3[0] << 20;
451 case ALU_ADD: mc = size == OP_SIZE_8 ? RISCV_ADD : RISCV_ADDW; break;
452 case ALU_SUB: mc = size == OP_SIZE_8 ? RISCV_SUB : RISCV_SUBW; break;
453 case ALU_XOR: mc = RISCV_XOR; break;
454 case ALU_OR: mc = RISCV_OR; break;
455 case ALU_AND: mc = RISCV_AND; break;
456 case ALU_ANDN: mc = RISCV_ANDN; break;
457 case ALU_MUL: mc = size == OP_SIZE_8 ? RISCV_MUL : RISCV_MULW; break;
458 case ALU_SMULH: if (unlikely(size != OP_SIZE_8))
460 mc = RISCV_MULH; break;
461 case ALU_UDIV: mc = size == OP_SIZE_8 ? RISCV_DIVU : RISCV_DIVUW; break;
462 case ALU_SDIV: mc = size == OP_SIZE_8 ? RISCV_DIV : RISCV_DIVW; break;
463 case ALU_UREM: mc = size == OP_SIZE_8 ? RISCV_REMU : RISCV_REMUW; break;
464 case ALU_SREM: mc = size == OP_SIZE_8 ? RISCV_REM : RISCV_REMW; break;
466 default: internal(file_line, "cgen_alu: invalid alu %u", alu);
468 mc |= (uint32_t)arg1[0] << 7;
469 mc |= (uint32_t)arg2[0] << 15;
470 mc |= (uint32_t)arg3[0] << 20;
475 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
479 uint8_t *arg1 = ctx->code_position;
480 uint8_t *arg2 = arg1 + arg_size(*arg1);
481 ctx->code_position = arg2 + arg_size(*arg2);
483 case ALU1_NOT: mc = RISCV_XORI | ((uint32_t)-1 << 20); break;
484 case ALU1_NEG: mc = (size == OP_SIZE_8 ? RISCV_SUB : RISCV_SUBW); tgt20 = true; break;
485 case ALU1_INC: mc = (size == OP_SIZE_8 ? RISCV_ADDI : RISCV_ADDIW) | ((uint32_t)1 << 20); break;
486 case ALU1_DEC: mc = (size == OP_SIZE_8 ? RISCV_ADDI : RISCV_ADDIW) | ((uint32_t)-1 << 20); break;
487 case ALU1_BSWAP:if (unlikely(size != OP_SIZE_8))
489 mc = RISCV_REV8; break;
490 case ALU1_BSF: mc = size == OP_SIZE_8 ? RISCV_CTZ : RISCV_CTZW; break;
491 case ALU1_LZCNT:mc = size == OP_SIZE_8 ? RISCV_CLZ : RISCV_CLZW; break;
492 case ALU1_POPCNT:mc = size == OP_SIZE_8 ? RISCV_CPOP : RISCV_CPOPW; break;
494 default: internal(file_line, "cgen_alu1: invalid alu %u", alu);
497 mc |= (uint32_t)arg1[0] << 7;
498 mc |= (uint32_t)arg2[0] << (tgt20 ? 20 : 15);
503 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
506 uint8_t *arg1 = ctx->code_position;
507 uint8_t *arg2 = arg1 + arg_size(*arg1);
508 uint8_t *arg3 = arg2 + arg_size(*arg2);
509 ctx->code_position = arg3 + arg_size(*arg3);
510 if (arg3[0] == ARG_IMM) {
511 int64_t imm = get_imm(&arg3[1]);
513 imm = -(uint64_t)imm;
514 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
516 case ROT_ROL: mc = size == OP_SIZE_4 ? RISCV_RORIW : RISCV_RORI; break;
517 case ROT_ROR: mc = size == OP_SIZE_4 ? RISCV_RORIW : RISCV_RORI; break;
518 case ROT_SHL: mc = size == OP_SIZE_4 ? RISCV_SLLIW : RISCV_SLLI; break;
519 case ROT_SHR: mc = size == OP_SIZE_4 ? RISCV_SRLIW : RISCV_SRLI; break;
520 case ROT_SAR: mc = size == OP_SIZE_4 ? RISCV_SRAIW : RISCV_SRAI; break;
521 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
523 mc |= (uint32_t)arg1[0] << 7;
524 mc |= (uint32_t)arg2[0] << 15;
525 mc |= (uint32_t)imm << 20;
530 case ROT_ROL: mc = size == OP_SIZE_4 ? RISCV_ROLW : RISCV_ROL; break;
531 case ROT_ROR: mc = size == OP_SIZE_4 ? RISCV_RORW : RISCV_ROR; break;
532 case ROT_SHL: mc = size == OP_SIZE_4 ? RISCV_SLLW : RISCV_SLL; break;
533 case ROT_SHR: mc = size == OP_SIZE_4 ? RISCV_SRLW : RISCV_SRL; break;
534 case ROT_SAR: mc = size == OP_SIZE_4 ? RISCV_SRAW : RISCV_SRA; break;
535 default: internal(file_line, "cgen_rot: invalid alu %u", alu);
537 mc |= (uint32_t)arg1[0] << 7;
538 mc |= (uint32_t)arg2[0] << 15;
539 mc |= (uint32_t)arg3[0] << 20;
544 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
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 (arg3[0] == ARG_IMM) {
552 int64_t imm = get_imm(&arg3[1]) & 0x3f;
554 case BTX_BTS: mc = RISCV_BSETI; break;
555 case BTX_BTR: mc = RISCV_BCLRI; break;
556 case BTX_BTC: mc = RISCV_BINVI; break;
557 case BTX_BTEXT: mc = RISCV_BEXTI; break;
558 default: internal(file_line, "cgen_btx: invalid alu %u", alu);
560 mc |= (uint32_t)arg1[0] << 7;
561 mc |= (uint32_t)arg2[0] << 15;
562 mc |= (uint32_t)imm << 20;
567 case BTX_BTS: mc = RISCV_BSET; break;
568 case BTX_BTR: mc = RISCV_BCLR; break;
569 case BTX_BTC: mc = RISCV_BINV; break;
570 case BTX_BTEXT: mc = RISCV_BEXT; break;
571 default: internal(file_line, "cgen_btx: invalid alu %u", alu);
573 mc |= (uint32_t)arg1[0] << 7;
574 mc |= (uint32_t)arg2[0] << 15;
575 mc |= (uint32_t)arg3[0] << 20;
580 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned aux)
584 uint8_t *arg1 = ctx->code_position;
585 uint8_t *arg2 = arg1 + arg_size(*arg1);
586 uint8_t *arg3 = arg2 + arg_size(*arg2);
587 ctx->code_position = arg3 + arg_size(*arg3);
589 case FP_COND_E: mc = RISCV_FEQ; break;
590 case FP_COND_A: mc = RISCV_FLT; swap = true; break;
591 case FP_COND_BE: mc = RISCV_FLE; break;
592 case FP_COND_B: mc = RISCV_FLT; break;
593 case FP_COND_AE: mc = RISCV_FLE; swap = true; break;
594 default: internal(file_line, "cgen_fp_cmp_dest_reg: invalid condition %u", aux);
597 uint8_t *argx = arg2;
602 case OP_SIZE_2: mc |= RISCV_F_HALF; break;
603 case OP_SIZE_4: mc |= RISCV_F_SINGLE; break;
604 case OP_SIZE_8: mc |= RISCV_F_DOUBLE; break;
605 case OP_SIZE_16: mc |= RISCV_F_QUAD; break;
606 default: internal(file_line, "cgen_fp_cmp_dest_reg: invalid size %u", op_size);
608 mc |= (uint32_t)arg1[0] << 7;
609 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
610 mc |= (uint32_t)(arg3[0] & 0x1f) << 20;
615 static uint32_t riscv_fp_op_size(unsigned fp_op_size)
617 switch (fp_op_size) {
618 case OP_SIZE_2: return RISCV_F_HALF;
619 case OP_SIZE_4: return RISCV_F_SINGLE;
620 case OP_SIZE_8: return RISCV_F_DOUBLE;
621 case OP_SIZE_16: return RISCV_F_QUAD;
622 default: internal(file_line, "riscv_fp_op_size: invalid size %u", fp_op_size);
627 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
630 uint8_t *arg1 = ctx->code_position;
631 uint8_t *arg2 = arg1 + arg_size(*arg1);
632 uint8_t *arg3 = arg2 + arg_size(*arg2);
633 ctx->code_position = arg3 + arg_size(*arg3);
635 case FP_ALU_ADD: mc = RISCV_FADD; break;
636 case FP_ALU_SUB: mc = RISCV_FSUB; break;
637 case FP_ALU_MUL: mc = RISCV_FMUL; break;
638 case FP_ALU_DIV: mc = RISCV_FDIV; break;
639 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
642 mc |= riscv_fp_op_size(op_size);
643 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
644 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
645 mc |= (uint32_t)(arg3[0] & 0x1f) << 20;
650 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
653 uint8_t *arg1 = ctx->code_position;
654 uint8_t *arg2 = arg1 + arg_size(*arg1);
655 ctx->code_position = arg2 + arg_size(*arg2);
657 case FP_ALU1_NEG: mc = RISCV_FSGNJN;
658 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
659 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
660 mc |= (uint32_t)(arg2[0] & 0x1f) << 20;
662 case FP_ALU1_SQRT: mc = RISCV_FSQRT;
663 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
664 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
667 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
669 mc |= riscv_fp_op_size(op_size);
674 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
677 uint8_t *arg1 = ctx->code_position;
678 uint8_t *arg2 = arg1 + arg_size(*arg1);
679 ctx->code_position = arg2 + arg_size(*arg2);
680 switch (int_op_size) {
681 case OP_SIZE_4: mc = RISCV_FCVT_TO_W; break;
682 case OP_SIZE_8: mc = RISCV_FCVT_TO_L; break;
683 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
686 mc |= riscv_fp_op_size(fp_op_size);
687 mc |= (uint32_t)arg1[0] << 7;
688 mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
693 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
696 uint8_t *arg1 = ctx->code_position;
697 uint8_t *arg2 = arg1 + arg_size(*arg1);
698 ctx->code_position = arg2 + arg_size(*arg2);
699 switch (int_op_size) {
700 case OP_SIZE_4: mc = RISCV_FCVT_FROM_W; break;
701 case OP_SIZE_8: mc = RISCV_FCVT_FROM_L; break;
702 default: internal(file_line, "cgen_fp_from_int: invalid int size %u", int_op_size);
705 mc |= riscv_fp_op_size(fp_op_size);
706 mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
707 mc |= (uint32_t)arg2[0] << 15;
712 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
714 if (length == JMP_SHORTEST && likely(cpu_test_feature(CPU_FEATURE_c))) {
715 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
717 } else if (length <= JMP_LONG) {
718 g(add_relocation(ctx, JMP_LONG, 0, NULL));
719 cgen_four(RISCV_JAL);
720 } else if (length == JMP_EXTRA_LONG) {
721 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
722 cgen_four(RISCV_AUIPC | ((uint32_t)R_CONST_HELPER << 7));
723 cgen_four(RISCV_JALR | ((uint32_t)R_CONST_HELPER << 15));
725 internal(file_line, "cgen_jmp: invalid length %u", length);
730 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
734 if (length > JMP_SHORT)
737 case COND_B: mc = RISCV_BLTU; break;
738 case COND_AE: mc = RISCV_BGEU; break;
739 case COND_E: mc = RISCV_BEQ; break;
740 case COND_NE: mc = RISCV_BNE; break;
741 case COND_BE: mc = RISCV_BGEU; swap = true; break;
742 case COND_A: mc = RISCV_BLTU; swap = true; break;
744 case COND_L: mc = RISCV_BLT; break;
746 case COND_GE: mc = RISCV_BGE; break;
747 case COND_LE: mc = RISCV_BGE; swap = true; break;
748 case COND_G: mc = RISCV_BLT; swap = true; break;
749 default: goto invalid;
752 unsigned regx = reg1;
757 mc |= (uint32_t)reg1 << 15;
758 mc |= (uint32_t)reg2 << 20;
760 if (length == JMP_SHORTEST && (cond == COND_E || cond == COND_NE) && (reg1 & 0x18) == 0x8 && reg2 == R_ZERO && cpu_test_feature(CPU_FEATURE_c)) {
761 uint16_t mc2 = cond == COND_E ? RISCV_C_BEQZ : RISCV_C_BNEZ;
762 mc2 |= ((uint16_t)reg1 & 0x7) << 7;
763 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
765 } else if (length <= JMP_SHORT) {
766 g(add_relocation(ctx, JMP_SHORT, reloc_offset, NULL));
768 } else if (length == JMP_LONG) {
771 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
774 } else if (length == JMP_EXTRA_LONG) {
777 g(add_relocation(ctx, JMP_EXTRA_LONG, reloc_offset, NULL));
778 cgen_four(RISCV_AUIPC | ((uint32_t)R_CONST_HELPER << 7));
779 cgen_four(RISCV_JALR | ((uint32_t)R_CONST_HELPER << 15));
781 internal(file_line, "cgen_jmp_12regs: invalid length %u", length);
786 internal(file_line, "cgen_jmp_12regs: invalid arguments %u, %02x, %02x", cond, reg1, reg2);
790 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
792 uint8_t *arg1 = ctx->code_position;
793 ctx->code_position = arg1 + arg_size(*arg1);
794 if (arg1[0] < 0x20) {
795 return cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1);
797 internal(file_line, "cgen_jmp_reg: invalid argument %02x", arg1[0]);
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 if (arg1[0] < 0x20 && arg2[0] < 0x20) {
807 return cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2);
809 internal(file_line, "cgen_jmp_2regs: invalid arguments %02x, %02x", arg1[0], arg2[0]);
814 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
819 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 1) - (int64_t)(reloc->position >> 1);
820 switch (reloc->length) {
822 memcpy(&mc2, ctx->mcode + reloc->position, 2);
823 if ((mc2 & 0xe003) == RISCV_C_J) {
824 if (unlikely(offs < -0x400) || unlikely(offs >= 0x400))
827 mc2 |= ((uint32_t)offs & 0x7) << 3;
828 mc2 |= ((uint32_t)offs & 0x8) << 8;
829 mc2 |= ((uint32_t)offs & 0x10) >> 2;
830 mc2 |= ((uint32_t)offs & 0x20) << 2;
831 mc2 |= ((uint32_t)offs & 0x40);
832 mc2 |= ((uint32_t)offs & 0x180) << 2;
833 mc2 |= ((uint32_t)offs & 0x200) >> 1;
834 mc2 |= ((uint32_t)offs & 0x400) << 2;
835 } else if ((mc2 & 0xe003) == RISCV_C_BEQZ || (mc2 & 0xe003) == RISCV_C_BNEZ) {
836 if (unlikely(offs < -0x80) || unlikely(offs >= 0x80))
839 mc2 |= ((uint32_t)offs & 0x3) << 3;
840 mc2 |= ((uint32_t)offs & 0xc) << 8;
841 mc2 |= ((uint32_t)offs & 0x10) >> 2;
842 mc2 |= ((uint32_t)offs & 0x60);
843 mc2 |= ((uint32_t)offs & 0x80) << 5;
845 internal(file_line, "resolve_relocation: invalid 2-byte instruction %04x", mc2);
847 memcpy(ctx->mcode + reloc->position, &mc2, 2);
850 if (unlikely(offs < -0x800) || unlikely(offs >= 0x800))
852 memcpy(&mc, ctx->mcode + reloc->position, 4);
854 mc |= ((uint32_t)offs & 0xf) << (8 - 0);
855 mc |= ((uint32_t)offs & 0x3f0) << (25 - 4);
856 mc |= ((uint32_t)offs & 0x400) >> (10 - 7);
857 mc |= ((uint32_t)offs & 0x800) << (31 - 11);
858 memcpy(ctx->mcode + reloc->position, &mc, 4);
861 if (unlikely(offs < -0x80000) || unlikely(offs >= 0x80000))
863 memcpy(&mc, ctx->mcode + reloc->position, 4);
865 mc |= ((uint32_t)offs & 0x3ff) << (21 - 0);
866 mc |= ((uint32_t)offs & 0x400) << (20 - 10);
867 mc |= ((uint32_t)offs & 0x7f800) << (12 - 11);
868 mc |= ((uint32_t)offs & 0x80000) << (31 - 19);
869 memcpy(ctx->mcode + reloc->position, &mc, 4);
872 offs = (uint64_t)offs << 1;
873 memcpy(&mc8, ctx->mcode + reloc->position, 8);
874 mc8 &= 0x000fffff00000fffULL;
875 mc8 |= ((uint64_t)offs & 0xfffULL) << (32 + 20);
877 offs = (uint64_t)offs + 0x1000;
879 if (unlikely(offs < -0x80000000LL) || unlikely(offs >= 0x80000000LL))
881 mc8 |= ((uint64_t)offs & 0xfffff000ULL);
882 memcpy(ctx->mcode + reloc->position, &mc8, 8);
885 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
890 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
892 if (unlikely(insn_writes_flags(insn)))
894 /*debug("insn: %08x", (unsigned)insn);*/
895 switch (insn_opcode(insn)) {
903 cgen_rv(RISCV_JALR | ((uint32_t)R_RA << 15));
905 case INSN_CALL_INDIRECT:
906 g(cgen_jmp_call_indirect(ctx, true));
909 g(cgen_mov(ctx, insn_op_size(insn)));
912 g(cgen_movsx(ctx, insn_op_size(insn)));
914 case INSN_CMP_DEST_REG:
915 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
917 g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
920 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
922 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
925 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
927 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
930 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
932 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
935 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
937 g(cgen_btx(ctx, insn_aux(insn)));
939 case INSN_FP_CMP_DEST_REG:
940 g(cgen_fp_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
943 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
946 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
948 case INSN_FP_TO_INT32:
949 case INSN_FP_TO_INT64:
950 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
952 case INSN_FP_FROM_INT32:
953 case INSN_FP_FROM_INT64:
954 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
957 g(cgen_jmp(ctx, insn_jump_size(insn)));
960 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
962 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
965 if (unlikely(insn_op_size(insn) != OP_SIZE_8))
967 g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
969 case INSN_JMP_INDIRECT:
970 g(cgen_jmp_call_indirect(ctx, false));
974 internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);