Ajla 0.1.5
[ajla.git] / c2-riscv.inc
blob77a22a662c4ba23e258a9ce5fb421eab0d863367
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
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
9  * version.
10  *
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.
14  *
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/>.
17  */
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))) {
147                 size_t result;
148                 uint16_t 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;
151                 cgen_two(c);
152                 return true;
153          }
154 uncompressed:
155         cgen_four(insn);
156         return true;
159 #define cgen_rv(dword)                                  \
160 do {                                                    \
161         if (unlikely(!cgen_rv_compress(ctx, dword)))    \
162                 return false;                           \
163 } while (0)
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;
173         cgen_rv(mc);
174         return true;
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;
185         cgen_rv(mc);
186         return true;
189 static bool attr_w cgen_jmp_call_indirect(struct codegen_context *ctx, bool call)
191         uint8_t reg = cget_one(ctx);
192         uint32_t mc;
193         mc = RISCV_JALR;
194         if (call)
195                 mc |= (uint32_t)R_RA << 7;
196         mc |= (uint32_t)reg << 15;
197         cgen_rv(mc);
198         return true;
201 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
203         uint32_t mc;
204         int64_t imm;
205         uint8_t z = R_ZERO;
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);
216                         mc = RISCV_LUI;
217                         mc |= (uint32_t)arg1[0] << 7;
218                         mc |= (uint32_t)imm;
219                         cgen_rv(mc);
220                         return true;
221                 }
222                 if (arg2[0] == ARG_ADDRESS_1) {
223                         imm = get_imm(&arg2[2]);
224                         switch (size) {
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;
230                         }
231                         g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], imm));
232                         return true;
233                 }
234                 if (arg2[0] < 0x20) {
235                         switch (size) {
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;
241                         }
242                         mc |= (uint32_t)arg1[0] << 7;
243                         mc |= (uint32_t)arg2[0] << 15;
244                         cgen_rv(mc);
245                         return true;
246                 }
247                 goto invalid;
248         }
249         if (arg1[0] < 0x40) {
250                 if (arg2[0] == ARG_ADDRESS_1) {
251                         imm = get_imm(&arg2[2]);
252                         switch (size) {
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;
258                         }
259                         g(cgen_memory_load(ctx, mc, arg1[0] & 0x1f, arg2[1], imm));
260                         return true;
261                 }
262                 goto invalid;
263         }
264         if (arg1[0] == ARG_ADDRESS_1) {
265                 if (arg2[0] == ARG_IMM) {
266                         imm = get_imm(&arg2[1]);
267                         if (unlikely(imm != 0))
268                                 goto invalid;
269                         arg2 = &z;
270                 }
271                 if (arg2[0] < 0x20) {
272                         imm = get_imm(&arg1[2]);
273                         switch (size) {
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;
279                         }
280                         g(cgen_memory_store(ctx, mc, arg1[1], arg2[0], imm));
281                         return true;
282                 }
283                 if (arg2[0] < 0x40) {
284                         imm = get_imm(&arg1[2]);
285                         switch (size) {
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;
291                         }
292                         g(cgen_memory_store(ctx, mc, arg1[1], arg2[0] & 0x1f, imm));
293                         return true;
294                 }
295                 goto invalid;
296         }
298 invalid:
299         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
300         return false;
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));
308                 return true;
309         }
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))
315                 goto invalid;
317         if (arg2[0] == ARG_ADDRESS_1) {
318                 uint32_t mc;
319                 switch (size) {
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;
324                 }
325                 g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], get_imm(&arg2[2])));
326                 return true;
327         }
329         if (arg2[0] < 0x20) {
330                 uint32_t mc;
331                 switch (size) {
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;
336                 }
337                 mc |= (uint32_t)arg1[0] << 7;
338                 mc |= (uint32_t)arg2[0] << 15;
339                 cgen_rv(mc);
340                 return true;
341         }
343 invalid:
344         internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, arg1[0], arg2[0]);
345         return false;
348 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
350         uint32_t mc;
351         bool swap = false;
352         uint8_t z = R_ZERO;
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);
361                 switch (aux) {
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);
365                 }
366                 mc |= (uint32_t)arg1[0] << 7;
367                 mc |= (uint32_t)arg2[0] << 15;
368                 mc |= (uint32_t)imm << 20;
369                 cgen_rv(mc);
370                 return true;
371         }
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");
376                 arg2 = &z;
377         }
378         switch (aux) {
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);
384         }
385         if (swap) {
386                 uint8_t *argx = arg2;
387                 arg2 = arg3;
388                 arg3 = argx;
389         }
390         mc |= (uint32_t)arg1[0] << 7;
391         mc |= (uint32_t)arg2[0] << 15;
392         mc |= (uint32_t)arg3[0] << 20;
393         cgen_rv(mc);
394         return true;
397 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
399         uint32_t mc;
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;
409                         alu = ALU_ADD;
410                 }
411                 if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
412                         internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
413                 switch (alu) {
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);
419                 }
420                 mc |= (uint32_t)arg1[0] << 7;
421                 mc |= (uint32_t)arg2[0] << 15;
422                 mc |= (uint32_t)imm << 20;
423                 cgen_rv(mc);
424                 return true;
425         }
426         if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
427                 uint8_t *arg_swp = arg3;
428                 arg3 = arg2;
429                 arg2 = arg_swp;
430         }
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))
435                         mc = RISCV_ADD;
436                 else if (arg2[1] == (ARG_SHIFT_LSL | 1))
437                         mc = RISCV_SH1ADD;
438                 else if (arg2[1] == (ARG_SHIFT_LSL | 2))
439                         mc = RISCV_SH2ADD;
440                 else if (arg2[1] == (ARG_SHIFT_LSL | 3))
441                         mc = RISCV_SH3ADD;
442                 else
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;
447                 cgen_rv(mc);
448                 return true;
449         }
450         switch (alu) {
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))
459                                         goto invalid;
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;
465                 invalid:
466                 default:        internal(file_line, "cgen_alu: invalid alu %u", alu);
467         }
468         mc |= (uint32_t)arg1[0] << 7;
469         mc |= (uint32_t)arg2[0] << 15;
470         mc |= (uint32_t)arg3[0] << 20;
471         cgen_rv(mc);
472         return true;
475 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
477         bool tgt20 = false;
478         uint32_t mc;
479         uint8_t *arg1 = ctx->code_position;
480         uint8_t *arg2 = arg1 + arg_size(*arg1);
481         ctx->code_position = arg2 + arg_size(*arg2);
482         switch (alu) {
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))
488                                         goto invalid;
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;
493                 invalid:
494                 default:        internal(file_line, "cgen_alu1: invalid alu %u", alu);
495                                 return false;
496         }
497         mc |= (uint32_t)arg1[0] << 7;
498         mc |= (uint32_t)arg2[0] << (tgt20 ? 20 : 15);
499         cgen_rv(mc);
500         return true;
503 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
505         uint32_t mc;
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]);
512                 if (alu == ROT_ROL)
513                         imm = -(uint64_t)imm;
514                 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
515                 switch (alu) {
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);
522                 }
523                 mc |= (uint32_t)arg1[0] << 7;
524                 mc |= (uint32_t)arg2[0] << 15;
525                 mc |= (uint32_t)imm << 20;
526                 cgen_rv(mc);
527                 return true;
528         }
529         switch (alu) {
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);
536         }
537         mc |= (uint32_t)arg1[0] << 7;
538         mc |= (uint32_t)arg2[0] << 15;
539         mc |= (uint32_t)arg3[0] << 20;
540         cgen_rv(mc);
541         return true;
544 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
546         uint32_t mc;
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;
553                 switch (alu) {
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);
559                 }
560                 mc |= (uint32_t)arg1[0] << 7;
561                 mc |= (uint32_t)arg2[0] << 15;
562                 mc |= (uint32_t)imm << 20;
563                 cgen_rv(mc);
564                 return true;
565         }
566         switch (alu) {
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);
572         }
573         mc |= (uint32_t)arg1[0] << 7;
574         mc |= (uint32_t)arg2[0] << 15;
575         mc |= (uint32_t)arg3[0] << 20;
576         cgen_rv(mc);
577         return true;
580 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned aux)
582         uint32_t mc;
583         bool swap = false;
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);
588         switch (aux) {
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);
595         }
596         if (swap) {
597                 uint8_t *argx = arg2;
598                 arg2 = arg3;
599                 arg3 = argx;
600         }
601         switch (op_size) {
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);
607         }
608         mc |= (uint32_t)arg1[0] << 7;
609         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
610         mc |= (uint32_t)(arg3[0] & 0x1f) << 20;
611         cgen_rv(mc);
612         return true;
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);
623         }
624         return (uint32_t)-1;
627 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
629         uint32_t mc;
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);
634         switch (aux) {
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);
640         }
641         mc |= RISCV_F_RNE;
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;
646         cgen_rv(mc);
647         return true;
650 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
652         uint32_t mc;
653         uint8_t *arg1 = ctx->code_position;
654         uint8_t *arg2 = arg1 + arg_size(*arg1);
655         ctx->code_position = arg2 + arg_size(*arg2);
656         switch (aux) {
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;
661                                         break;
662                 case FP_ALU1_SQRT:      mc = RISCV_FSQRT;
663                                         mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
664                                         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
665                                         mc |= RISCV_F_RNE;
666                                         break;
667                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
668         }
669         mc |= riscv_fp_op_size(op_size);
670         cgen_rv(mc);
671         return true;
674 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
676         uint32_t mc;
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);
684         }
685         mc |= RISCV_F_RTZ;
686         mc |= riscv_fp_op_size(fp_op_size);
687         mc |= (uint32_t)arg1[0] << 7;
688         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
689         cgen_rv(mc);
690         return true;
693 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
695         uint32_t mc;
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);
703         }
704         mc |= RISCV_F_RNE;
705         mc |= riscv_fp_op_size(fp_op_size);
706         mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
707         mc |= (uint32_t)arg2[0] << 15;
708         cgen_rv(mc);
709         return true;
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));
716                 cgen_two(RISCV_C_J);
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));
724         } else {
725                 internal(file_line, "cgen_jmp: invalid length %u", length);
726         }
727         return true;
730 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
732         uint32_t mc;
733         bool swap = false;
734         if (length > JMP_SHORT)
735                 cond ^= 1;
736         switch (cond) {
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;
743                 case COND_S:
744                 case COND_L:    mc = RISCV_BLT; break;
745                 case COND_NS:
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;
750         }
751         if (swap) {
752                 unsigned regx = reg1;
753                 reg1 = reg2;
754                 reg2 = regx;
755         }
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));
764                 cgen_two(mc2);
765         } else if (length <= JMP_SHORT) {
766                 g(add_relocation(ctx, JMP_SHORT, reloc_offset, NULL));
767                 cgen_four(mc);
768         } else if (length == JMP_LONG) {
769                 mc |= 0x400;
770                 cgen_four(mc);
771                 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
772                 mc = RISCV_JAL;
773                 cgen_four(mc);
774         } else if (length == JMP_EXTRA_LONG) {
775                 mc |= 0x600;
776                 cgen_four(mc);
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));
780         } else {
781                 internal(file_line, "cgen_jmp_12regs: invalid length %u", length);
782         }
783         return true;
785 invalid:
786         internal(file_line, "cgen_jmp_12regs: invalid arguments %u, %02x, %02x", cond, reg1, reg2);
787         return false;
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);
796         }
797         internal(file_line, "cgen_jmp_reg: invalid argument %02x", arg1[0]);
798         return false;
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);
808         }
809         internal(file_line, "cgen_jmp_2regs: invalid arguments %02x, %02x", arg1[0], arg2[0]);
810         return false;
814 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
816         uint16_t mc2;
817         uint32_t mc;
818         uint64_t mc8;
819         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 1) - (int64_t)(reloc->position >> 1);
820         switch (reloc->length) {
821                 case JMP_SHORTEST:
822                         memcpy(&mc2, ctx->mcode + reloc->position, 2);
823                         if ((mc2 & 0xe003) == RISCV_C_J) {
824                                 if (unlikely(offs < -0x400) || unlikely(offs >= 0x400))
825                                         return false;
826                                 mc2 &= 0xe003;
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))
837                                         return false;
838                                 mc2 &= 0xe383;
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;
844                         } else {
845                                 internal(file_line, "resolve_relocation: invalid 2-byte instruction %04x", mc2);
846                         }
847                         memcpy(ctx->mcode + reloc->position, &mc2, 2);
848                         return true;
849                 case JMP_SHORT:
850                         if (unlikely(offs < -0x800) || unlikely(offs >= 0x800))
851                                 return false;
852                         memcpy(&mc, ctx->mcode + reloc->position, 4);
853                         mc &= 0x01fff07fU;
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);
859                         return true;
860                 case JMP_LONG:
861                         if (unlikely(offs < -0x80000) || unlikely(offs >= 0x80000))
862                                 return false;
863                         memcpy(&mc, ctx->mcode + reloc->position, 4);
864                         mc &= 0x00000fffU;
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);
870                         return true;
871                 case JMP_EXTRA_LONG:
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);
876                         if (offs & 0x800) {
877                                 offs = (uint64_t)offs + 0x1000;
878                         }
879                         if (unlikely(offs < -0x80000000LL) || unlikely(offs >= 0x80000000LL))
880                                 return false;
881                         mc8 |= ((uint64_t)offs & 0xfffff000ULL);
882                         memcpy(ctx->mcode + reloc->position, &mc8, 8);
883                         return true;
884                 default:
885                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
886         }
887         return false;
890 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
892         if (unlikely(insn_writes_flags(insn)))
893                 goto invalid_insn;
894         /*debug("insn: %08x", (unsigned)insn);*/
895         switch (insn_opcode(insn)) {
896                 case INSN_ENTRY:
897                         g(cgen_entry(ctx));
898                         return true;
899                 case INSN_LABEL:
900                         g(cgen_label(ctx));
901                         return true;
902                 case INSN_RET:
903                         cgen_rv(RISCV_JALR | ((uint32_t)R_RA << 15));
904                         return true;
905                 case INSN_CALL_INDIRECT:
906                         g(cgen_jmp_call_indirect(ctx, true));
907                         return true;
908                 case INSN_MOV:
909                         g(cgen_mov(ctx, insn_op_size(insn)));
910                         return true;
911                 case INSN_MOVSX:
912                         g(cgen_movsx(ctx, insn_op_size(insn)));
913                         return true;
914                 case INSN_CMP_DEST_REG:
915                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
916                                 goto invalid_insn;
917                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
918                         return true;
919                 case INSN_ALU:
920                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
921                                 goto invalid_insn;
922                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
923                         return true;
924                 case INSN_ALU1:
925                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
926                                 goto invalid_insn;
927                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
928                         return true;
929                 case INSN_ROT:
930                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
931                                 goto invalid_insn;
932                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
933                         return true;
934                 case INSN_BTX:
935                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
936                                 goto invalid_insn;
937                         g(cgen_btx(ctx, insn_aux(insn)));
938                         return true;
939                 case INSN_FP_CMP_DEST_REG:
940                         g(cgen_fp_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
941                         return true;
942                 case INSN_FP_ALU:
943                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
944                         return true;
945                 case INSN_FP_ALU1:
946                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
947                         return true;
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)));
951                         return true;
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)));
955                         return true;
956                 case INSN_JMP:
957                         g(cgen_jmp(ctx, insn_jump_size(insn)));
958                         return true;
959                 case INSN_JMP_REG:
960                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
961                                 goto invalid_insn;
962                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
963                         return true;
964                 case INSN_JMP_2REGS:
965                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
966                                 goto invalid_insn;
967                         g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
968                         return true;
969                 case INSN_JMP_INDIRECT:
970                         g(cgen_jmp_call_indirect(ctx, false));
971                         return true;
972                 default:
973                 invalid_insn:
974                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
975                         return false;
976         }