codegen: rework ALU_WRITES_FLAGS so that it takes four arguments: alu,
[ajla.git] / c2-riscv.inc
blob4fe8220cca3b8aa0b80d0187c55b1ac8da9b6782
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 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);
209         }
210         return (uint32_t)-1;
213 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
215         uint32_t mc;
216         int64_t imm;
217         uint8_t z = R_ZERO;
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);
228                         mc = RISCV_LUI;
229                         mc |= (uint32_t)arg1[0] << 7;
230                         mc |= (uint32_t)imm;
231                         cgen_rv(mc);
232                         return true;
233                 }
234                 if (arg2[0] == ARG_ADDRESS_1) {
235                         imm = get_imm(&arg2[2]);
236                         switch (size) {
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;
242                         }
243                         g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], imm));
244                         return true;
245                 }
246                 if (arg2[0] < 0x20) {
247                         switch (size) {
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;
253                         }
254                         mc |= (uint32_t)arg1[0] << 7;
255                         mc |= (uint32_t)arg2[0] << 15;
256                         cgen_rv(mc);
257                         return true;
258                 }
259                 goto invalid;
260         }
261         if (reg_is_fp(arg1[0])) {
262                 if (reg_is_fp(arg2[0])) {
263                         mc = RISCV_FSGNJ;
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);
268                         cgen_rv(mc);
269                         return true;
270                 }
271                 if (arg2[0] == ARG_ADDRESS_1) {
272                         imm = get_imm(&arg2[2]);
273                         switch (size) {
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;
279                         }
280                         g(cgen_memory_load(ctx, mc, arg1[0] & 0x1f, arg2[1], imm));
281                         return true;
282                 }
283                 goto invalid;
284         }
285         if (arg1[0] == ARG_ADDRESS_1) {
286                 if (arg2[0] == ARG_IMM) {
287                         imm = get_imm(&arg2[1]);
288                         if (unlikely(imm != 0))
289                                 goto invalid;
290                         arg2 = &z;
291                 }
292                 if (arg2[0] < 0x20) {
293                         imm = get_imm(&arg1[2]);
294                         switch (size) {
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;
300                         }
301                         g(cgen_memory_store(ctx, mc, arg1[1], arg2[0], imm));
302                         return true;
303                 }
304                 if (reg_is_fp(arg2[0])) {
305                         imm = get_imm(&arg1[2]);
306                         switch (size) {
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;
312                         }
313                         g(cgen_memory_store(ctx, mc, arg1[1], arg2[0] & 0x1f, imm));
314                         return true;
315                 }
316                 goto invalid;
317         }
319 invalid:
320         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
321         return false;
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));
329                 return true;
330         }
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))
336                 goto invalid;
338         if (arg2[0] == ARG_ADDRESS_1) {
339                 uint32_t mc;
340                 switch (size) {
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;
345                 }
346                 g(cgen_memory_load(ctx, mc, arg1[0], arg2[1], get_imm(&arg2[2])));
347                 return true;
348         }
350         if (arg2[0] < 0x20) {
351                 uint32_t mc;
352                 switch (size) {
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;
357                 }
358                 mc |= (uint32_t)arg1[0] << 7;
359                 mc |= (uint32_t)arg2[0] << 15;
360                 cgen_rv(mc);
361                 return true;
362         }
364 invalid:
365         internal(file_line, "cgen_movsx: invalid parameters %u, %02x, %02x", size, arg1[0], arg2[0]);
366         return false;
369 static bool attr_w cgen_cmp_dest_reg(struct codegen_context *ctx, unsigned aux)
371         uint32_t mc;
372         bool swap = false;
373         uint8_t z = R_ZERO;
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);
382                 switch (aux) {
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);
386                 }
387                 mc |= (uint32_t)arg1[0] << 7;
388                 mc |= (uint32_t)arg2[0] << 15;
389                 mc |= (uint32_t)imm << 20;
390                 cgen_rv(mc);
391                 return true;
392         }
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");
397                 arg2 = &z;
398         }
399         switch (aux) {
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);
405         }
406         if (swap) {
407                 uint8_t *argx = arg2;
408                 arg2 = arg3;
409                 arg3 = argx;
410         }
411         mc |= (uint32_t)arg1[0] << 7;
412         mc |= (uint32_t)arg2[0] << 15;
413         mc |= (uint32_t)arg3[0] << 20;
414         cgen_rv(mc);
415         return true;
418 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
420         uint32_t mc;
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;
430                         alu = ALU_ADD;
431                 }
432                 if (unlikely(imm < -0x800) || unlikely(imm >= 0x800))
433                         internal(file_line, "cgen_alu: invalid imm value %"PRIxMAX"", (intmax_t)imm);
434                 switch (alu) {
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);
440                 }
441                 mc |= (uint32_t)arg1[0] << 7;
442                 mc |= (uint32_t)arg2[0] << 15;
443                 mc |= (uint32_t)imm << 20;
444                 cgen_rv(mc);
445                 return true;
446         }
447         if (alu == ALU_ADD && arg3[0] == ARG_SHIFTED_REGISTER) {
448                 uint8_t *arg_swp = arg3;
449                 arg3 = arg2;
450                 arg2 = arg_swp;
451         }
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))
456                         mc = RISCV_ADD;
457                 else if (arg2[1] == (ARG_SHIFT_LSL | 1))
458                         mc = RISCV_SH1ADD;
459                 else if (arg2[1] == (ARG_SHIFT_LSL | 2))
460                         mc = RISCV_SH2ADD;
461                 else if (arg2[1] == (ARG_SHIFT_LSL | 3))
462                         mc = RISCV_SH3ADD;
463                 else
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;
468                 cgen_rv(mc);
469                 return true;
470         }
471         switch (alu) {
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))
480                                         goto invalid;
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;
486                 invalid:
487                 default:        internal(file_line, "cgen_alu: invalid alu %u", alu);
488         }
489         mc |= (uint32_t)arg1[0] << 7;
490         mc |= (uint32_t)arg2[0] << 15;
491         mc |= (uint32_t)arg3[0] << 20;
492         cgen_rv(mc);
493         return true;
496 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
498         bool tgt20 = false;
499         uint32_t mc;
500         uint8_t *arg1 = ctx->code_position;
501         uint8_t *arg2 = arg1 + arg_size(*arg1);
502         ctx->code_position = arg2 + arg_size(*arg2);
503         switch (alu) {
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_BSWAP:if (unlikely(size != OP_SIZE_8))
507                                         goto invalid;
508                                 mc = RISCV_REV8; break;
509                 case ALU1_BSF:  mc = size == OP_SIZE_8 ? RISCV_CTZ : RISCV_CTZW; break;
510                 case ALU1_LZCNT:mc = size == OP_SIZE_8 ? RISCV_CLZ : RISCV_CLZW; break;
511                 case ALU1_POPCNT:mc = size == OP_SIZE_8 ? RISCV_CPOP : RISCV_CPOPW; break;
512                 invalid:
513                 default:        internal(file_line, "cgen_alu1: invalid alu %u", alu);
514                                 return false;
515         }
516         mc |= (uint32_t)arg1[0] << 7;
517         mc |= (uint32_t)arg2[0] << (tgt20 ? 20 : 15);
518         cgen_rv(mc);
519         return true;
522 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu)
524         uint32_t mc;
525         uint8_t *arg1 = ctx->code_position;
526         uint8_t *arg2 = arg1 + arg_size(*arg1);
527         uint8_t *arg3 = arg2 + arg_size(*arg2);
528         ctx->code_position = arg3 + arg_size(*arg3);
529         if (arg3[0] == ARG_IMM) {
530                 int64_t imm = get_imm(&arg3[1]);
531                 if (alu == ROT_ROL)
532                         imm = -(uint64_t)imm;
533                 imm &= size == OP_SIZE_4 ? 0x1f : 0x3f;
534                 switch (alu) {
535                         case ROT_ROL:   mc = size == OP_SIZE_4 ? RISCV_RORIW : RISCV_RORI; break;
536                         case ROT_ROR:   mc = size == OP_SIZE_4 ? RISCV_RORIW : RISCV_RORI; break;
537                         case ROT_SHL:   mc = size == OP_SIZE_4 ? RISCV_SLLIW : RISCV_SLLI; break;
538                         case ROT_SHR:   mc = size == OP_SIZE_4 ? RISCV_SRLIW : RISCV_SRLI; break;
539                         case ROT_SAR:   mc = size == OP_SIZE_4 ? RISCV_SRAIW : RISCV_SRAI; break;
540                         default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
541                 }
542                 mc |= (uint32_t)arg1[0] << 7;
543                 mc |= (uint32_t)arg2[0] << 15;
544                 mc |= (uint32_t)imm << 20;
545                 cgen_rv(mc);
546                 return true;
547         }
548         switch (alu) {
549                 case ROT_ROL:   mc = size == OP_SIZE_4 ? RISCV_ROLW : RISCV_ROL; break;
550                 case ROT_ROR:   mc = size == OP_SIZE_4 ? RISCV_RORW : RISCV_ROR; break;
551                 case ROT_SHL:   mc = size == OP_SIZE_4 ? RISCV_SLLW : RISCV_SLL; break;
552                 case ROT_SHR:   mc = size == OP_SIZE_4 ? RISCV_SRLW : RISCV_SRL; break;
553                 case ROT_SAR:   mc = size == OP_SIZE_4 ? RISCV_SRAW : RISCV_SRA; break;
554                 default:        internal(file_line, "cgen_rot: invalid alu %u", alu);
555         }
556         mc |= (uint32_t)arg1[0] << 7;
557         mc |= (uint32_t)arg2[0] << 15;
558         mc |= (uint32_t)arg3[0] << 20;
559         cgen_rv(mc);
560         return true;
563 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned alu)
565         uint32_t mc;
566         uint8_t *arg1 = ctx->code_position;
567         uint8_t *arg2 = arg1 + arg_size(*arg1);
568         uint8_t *arg3 = arg2 + arg_size(*arg2);
569         ctx->code_position = arg3 + arg_size(*arg3);
570         if (arg3[0] == ARG_IMM) {
571                 int64_t imm = get_imm(&arg3[1]) & 0x3f;
572                 switch (alu) {
573                         case BTX_BTS:   mc = RISCV_BSETI; break;
574                         case BTX_BTR:   mc = RISCV_BCLRI; break;
575                         case BTX_BTC:   mc = RISCV_BINVI; break;
576                         case BTX_BTEXT: mc = RISCV_BEXTI; break;
577                         default:        internal(file_line, "cgen_btx: invalid alu %u", alu);
578                 }
579                 mc |= (uint32_t)arg1[0] << 7;
580                 mc |= (uint32_t)arg2[0] << 15;
581                 mc |= (uint32_t)imm << 20;
582                 cgen_rv(mc);
583                 return true;
584         }
585         switch (alu) {
586                 case BTX_BTS:   mc = RISCV_BSET; break;
587                 case BTX_BTR:   mc = RISCV_BCLR; break;
588                 case BTX_BTC:   mc = RISCV_BINV; break;
589                 case BTX_BTEXT: mc = RISCV_BEXT; break;
590                 default:        internal(file_line, "cgen_btx: invalid alu %u", alu);
591         }
592         mc |= (uint32_t)arg1[0] << 7;
593         mc |= (uint32_t)arg2[0] << 15;
594         mc |= (uint32_t)arg3[0] << 20;
595         cgen_rv(mc);
596         return true;
599 static bool attr_w cgen_fp_cmp_dest_reg(struct codegen_context *ctx, unsigned op_size, unsigned aux)
601         uint32_t mc;
602         bool swap = false;
603         uint8_t *arg1 = ctx->code_position;
604         uint8_t *arg2 = arg1 + arg_size(*arg1);
605         uint8_t *arg3 = arg2 + arg_size(*arg2);
606         ctx->code_position = arg3 + arg_size(*arg3);
607         switch (aux) {
608                 case FP_COND_E:         mc = RISCV_FEQ; break;
609                 case FP_COND_A:         mc = RISCV_FLT; swap = true; break;
610                 case FP_COND_BE:        mc = RISCV_FLE; break;
611                 case FP_COND_B:         mc = RISCV_FLT; break;
612                 case FP_COND_AE:        mc = RISCV_FLE; swap = true; break;
613                 default:                internal(file_line, "cgen_fp_cmp_dest_reg: invalid condition %u", aux);
614         }
615         if (swap) {
616                 uint8_t *argx = arg2;
617                 arg2 = arg3;
618                 arg3 = argx;
619         }
620         switch (op_size) {
621                 case OP_SIZE_2:         mc |= RISCV_F_HALF; break;
622                 case OP_SIZE_4:         mc |= RISCV_F_SINGLE; break;
623                 case OP_SIZE_8:         mc |= RISCV_F_DOUBLE; break;
624                 case OP_SIZE_16:        mc |= RISCV_F_QUAD; break;
625                 default:                internal(file_line, "cgen_fp_cmp_dest_reg: invalid size %u", op_size);
626         }
627         mc |= (uint32_t)arg1[0] << 7;
628         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
629         mc |= (uint32_t)(arg3[0] & 0x1f) << 20;
630         cgen_rv(mc);
631         return true;
634 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
636         uint32_t mc;
637         uint8_t *arg1 = ctx->code_position;
638         uint8_t *arg2 = arg1 + arg_size(*arg1);
639         uint8_t *arg3 = arg2 + arg_size(*arg2);
640         ctx->code_position = arg3 + arg_size(*arg3);
641         switch (aux) {
642                 case FP_ALU_ADD:        mc = RISCV_FADD; break;
643                 case FP_ALU_SUB:        mc = RISCV_FSUB; break;
644                 case FP_ALU_MUL:        mc = RISCV_FMUL; break;
645                 case FP_ALU_DIV:        mc = RISCV_FDIV; break;
646                 default:                internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
647         }
648         mc |= RISCV_F_RNE;
649         mc |= riscv_fp_op_size(op_size);
650         mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
651         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
652         mc |= (uint32_t)(arg3[0] & 0x1f) << 20;
653         cgen_rv(mc);
654         return true;
657 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
659         uint32_t mc;
660         uint8_t *arg1 = ctx->code_position;
661         uint8_t *arg2 = arg1 + arg_size(*arg1);
662         ctx->code_position = arg2 + arg_size(*arg2);
663         switch (aux) {
664                 case FP_ALU1_NEG:       mc = RISCV_FSGNJN;
665                                         mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
666                                         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
667                                         mc |= (uint32_t)(arg2[0] & 0x1f) << 20;
668                                         break;
669                 case FP_ALU1_SQRT:      mc = RISCV_FSQRT;
670                                         mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
671                                         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
672                                         mc |= RISCV_F_RNE;
673                                         break;
674                 default:                internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
675         }
676         mc |= riscv_fp_op_size(op_size);
677         cgen_rv(mc);
678         return true;
681 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
683         uint32_t mc;
684         uint8_t *arg1 = ctx->code_position;
685         uint8_t *arg2 = arg1 + arg_size(*arg1);
686         ctx->code_position = arg2 + arg_size(*arg2);
687         switch (int_op_size) {
688                 case OP_SIZE_4: mc = RISCV_FCVT_TO_W; break;
689                 case OP_SIZE_8: mc = RISCV_FCVT_TO_L; break;
690                 default:        internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
691         }
692         mc |= RISCV_F_RTZ;
693         mc |= riscv_fp_op_size(fp_op_size);
694         mc |= (uint32_t)arg1[0] << 7;
695         mc |= (uint32_t)(arg2[0] & 0x1f) << 15;
696         cgen_rv(mc);
697         return true;
700 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
702         uint32_t mc;
703         uint8_t *arg1 = ctx->code_position;
704         uint8_t *arg2 = arg1 + arg_size(*arg1);
705         ctx->code_position = arg2 + arg_size(*arg2);
706         switch (int_op_size) {
707                 case OP_SIZE_4: mc = RISCV_FCVT_FROM_W; break;
708                 case OP_SIZE_8: mc = RISCV_FCVT_FROM_L; break;
709                 default:        internal(file_line, "cgen_fp_from_int: invalid int size %u", int_op_size);
710         }
711         mc |= RISCV_F_RNE;
712         mc |= riscv_fp_op_size(fp_op_size);
713         mc |= (uint32_t)(arg1[0] & 0x1f) << 7;
714         mc |= (uint32_t)arg2[0] << 15;
715         cgen_rv(mc);
716         return true;
719 static bool attr_w cgen_jmp(struct codegen_context *ctx, unsigned length)
721         if (length == JMP_SHORTEST && likely(cpu_test_feature(CPU_FEATURE_c))) {
722                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
723                 cgen_two(RISCV_C_J);
724         } else if (length <= JMP_LONG) {
725                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
726                 cgen_four(RISCV_JAL);
727         } else if (length == JMP_EXTRA_LONG) {
728                 g(add_relocation(ctx, JMP_EXTRA_LONG, 0, NULL));
729                 cgen_four(RISCV_AUIPC | ((uint32_t)R_CONST_HELPER << 7));
730                 cgen_four(RISCV_JALR | ((uint32_t)R_CONST_HELPER << 15));
731         } else {
732                 internal(file_line, "cgen_jmp: invalid length %u", length);
733         }
734         return true;
737 static bool attr_w cgen_jmp_12regs(struct codegen_context *ctx, unsigned cond, unsigned length, unsigned reg1, unsigned reg2, int reloc_offset)
739         uint32_t mc;
740         bool swap = false;
741         if (length > JMP_SHORT)
742                 cond ^= 1;
743         switch (cond) {
744                 case COND_B:    mc = RISCV_BLTU; break;
745                 case COND_AE:   mc = RISCV_BGEU; break;
746                 case COND_E:    mc = RISCV_BEQ; break;
747                 case COND_NE:   mc = RISCV_BNE; break;
748                 case COND_BE:   mc = RISCV_BGEU; swap = true; break;
749                 case COND_A:    mc = RISCV_BLTU; swap = true; break;
750                 case COND_S:
751                 case COND_L:    mc = RISCV_BLT; break;
752                 case COND_NS:
753                 case COND_GE:   mc = RISCV_BGE; break;
754                 case COND_LE:   mc = RISCV_BGE; swap = true; break;
755                 case COND_G:    mc = RISCV_BLT; swap = true; break;
756                 default:        goto invalid;
757         }
758         if (swap) {
759                 unsigned regx = reg1;
760                 reg1 = reg2;
761                 reg2 = regx;
762         }
764         mc |= (uint32_t)reg1 << 15;
765         mc |= (uint32_t)reg2 << 20;
767         if (length == JMP_SHORTEST && (cond == COND_E || cond == COND_NE) && (reg1 & 0x18) == 0x8 && reg2 == R_ZERO && cpu_test_feature(CPU_FEATURE_c)) {
768                 uint16_t mc2 = cond == COND_E ? RISCV_C_BEQZ : RISCV_C_BNEZ;
769                 mc2 |= ((uint16_t)reg1 & 0x7) << 7;
770                 g(add_relocation(ctx, JMP_SHORTEST, reloc_offset, NULL));
771                 cgen_two(mc2);
772         } else if (length <= JMP_SHORT) {
773                 g(add_relocation(ctx, JMP_SHORT, reloc_offset, NULL));
774                 cgen_four(mc);
775         } else if (length == JMP_LONG) {
776                 mc |= 0x400;
777                 cgen_four(mc);
778                 g(add_relocation(ctx, JMP_LONG, reloc_offset, NULL));
779                 mc = RISCV_JAL;
780                 cgen_four(mc);
781         } else if (length == JMP_EXTRA_LONG) {
782                 mc |= 0x600;
783                 cgen_four(mc);
784                 g(add_relocation(ctx, JMP_EXTRA_LONG, reloc_offset, NULL));
785                 cgen_four(RISCV_AUIPC | ((uint32_t)R_CONST_HELPER << 7));
786                 cgen_four(RISCV_JALR | ((uint32_t)R_CONST_HELPER << 15));
787         } else {
788                 internal(file_line, "cgen_jmp_12regs: invalid length %u", length);
789         }
790         return true;
792 invalid:
793         internal(file_line, "cgen_jmp_12regs: invalid arguments %u, %02x, %02x", cond, reg1, reg2);
794         return false;
797 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned cond, unsigned length)
799         uint8_t *arg1 = ctx->code_position;
800         ctx->code_position = arg1 + arg_size(*arg1);
801         if (arg1[0] < 0x20) {
802                 return cgen_jmp_12regs(ctx, cond, length, arg1[0], R_ZERO, 1);
803         }
804         internal(file_line, "cgen_jmp_reg: invalid argument %02x", arg1[0]);
805         return false;
808 static bool attr_w cgen_jmp_2regs(struct codegen_context *ctx, unsigned cond, unsigned length)
810         uint8_t *arg1 = ctx->code_position;
811         uint8_t *arg2 = arg1 + arg_size(*arg1);
812         ctx->code_position = arg2 + arg_size(*arg2);
813         if (arg1[0] < 0x20 && arg2[0] < 0x20) {
814                 return cgen_jmp_12regs(ctx, cond, length, arg1[0], arg2[0], 2);
815         }
816         internal(file_line, "cgen_jmp_2regs: invalid arguments %02x, %02x", arg1[0], arg2[0]);
817         return false;
821 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
823         uint16_t mc2;
824         uint32_t mc;
825         uint64_t mc8;
826         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 1) - (int64_t)(reloc->position >> 1);
827         switch (reloc->length) {
828                 case JMP_SHORTEST:
829                         memcpy(&mc2, ctx->mcode + reloc->position, 2);
830                         if ((mc2 & 0xe003) == RISCV_C_J) {
831                                 if (unlikely(offs < -0x400) || unlikely(offs >= 0x400))
832                                         return false;
833                                 mc2 &= 0xe003;
834                                 mc2 |= ((uint32_t)offs & 0x7) << 3;
835                                 mc2 |= ((uint32_t)offs & 0x8) << 8;
836                                 mc2 |= ((uint32_t)offs & 0x10) >> 2;
837                                 mc2 |= ((uint32_t)offs & 0x20) << 2;
838                                 mc2 |= ((uint32_t)offs & 0x40);
839                                 mc2 |= ((uint32_t)offs & 0x180) << 2;
840                                 mc2 |= ((uint32_t)offs & 0x200) >> 1;
841                                 mc2 |= ((uint32_t)offs & 0x400) << 2;
842                         } else if ((mc2 & 0xe003) == RISCV_C_BEQZ || (mc2 & 0xe003) == RISCV_C_BNEZ) {
843                                 if (unlikely(offs < -0x80) || unlikely(offs >= 0x80))
844                                         return false;
845                                 mc2 &= 0xe383;
846                                 mc2 |= ((uint32_t)offs & 0x3) << 3;
847                                 mc2 |= ((uint32_t)offs & 0xc) << 8;
848                                 mc2 |= ((uint32_t)offs & 0x10) >> 2;
849                                 mc2 |= ((uint32_t)offs & 0x60);
850                                 mc2 |= ((uint32_t)offs & 0x80) << 5;
851                         } else {
852                                 internal(file_line, "resolve_relocation: invalid 2-byte instruction %04x", mc2);
853                         }
854                         memcpy(ctx->mcode + reloc->position, &mc2, 2);
855                         return true;
856                 case JMP_SHORT:
857                         if (unlikely(offs < -0x800) || unlikely(offs >= 0x800))
858                                 return false;
859                         memcpy(&mc, ctx->mcode + reloc->position, 4);
860                         mc &= 0x01fff07fU;
861                         mc |= ((uint32_t)offs & 0xf) << (8 - 0);
862                         mc |= ((uint32_t)offs & 0x3f0) << (25 - 4);
863                         mc |= ((uint32_t)offs & 0x400) >> (10 - 7);
864                         mc |= ((uint32_t)offs & 0x800) << (31 - 11);
865                         memcpy(ctx->mcode + reloc->position, &mc, 4);
866                         return true;
867                 case JMP_LONG:
868                         if (unlikely(offs < -0x80000) || unlikely(offs >= 0x80000))
869                                 return false;
870                         memcpy(&mc, ctx->mcode + reloc->position, 4);
871                         mc &= 0x00000fffU;
872                         mc |= ((uint32_t)offs & 0x3ff) << (21 - 0);
873                         mc |= ((uint32_t)offs & 0x400) << (20 - 10);
874                         mc |= ((uint32_t)offs & 0x7f800) << (12 - 11);
875                         mc |= ((uint32_t)offs & 0x80000) << (31 - 19);
876                         memcpy(ctx->mcode + reloc->position, &mc, 4);
877                         return true;
878                 case JMP_EXTRA_LONG:
879                         offs = (uint64_t)offs << 1;
880                         memcpy(&mc8, ctx->mcode + reloc->position, 8);
881                         mc8 &= 0x000fffff00000fffULL;
882                         mc8 |= ((uint64_t)offs & 0xfffULL) << (32 + 20);
883                         if (offs & 0x800) {
884                                 offs = (uint64_t)offs + 0x1000;
885                         }
886                         if (unlikely(offs < -0x80000000LL) || unlikely(offs >= 0x80000000LL))
887                                 return false;
888                         mc8 |= ((uint64_t)offs & 0xfffff000ULL);
889                         memcpy(ctx->mcode + reloc->position, &mc8, 8);
890                         return true;
891                 default:
892                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
893         }
894         return false;
897 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
899         if (unlikely(insn_writes_flags(insn)))
900                 goto invalid_insn;
901         /*debug("insn: %08x", (unsigned)insn);*/
902         switch (insn_opcode(insn)) {
903                 case INSN_ENTRY:
904                         g(cgen_entry(ctx));
905                         return true;
906                 case INSN_LABEL:
907                         g(cgen_label(ctx));
908                         return true;
909                 case INSN_RET:
910                         cgen_rv(RISCV_JALR | ((uint32_t)R_RA << 15));
911                         return true;
912                 case INSN_CALL_INDIRECT:
913                         g(cgen_jmp_call_indirect(ctx, true));
914                         return true;
915                 case INSN_MOV:
916                         g(cgen_mov(ctx, insn_op_size(insn)));
917                         return true;
918                 case INSN_MOVSX:
919                         g(cgen_movsx(ctx, insn_op_size(insn)));
920                         return true;
921                 case INSN_CMP_DEST_REG:
922                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
923                                 goto invalid_insn;
924                         g(cgen_cmp_dest_reg(ctx, insn_aux(insn)));
925                         return true;
926                 case INSN_ALU:
927                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
928                                 goto invalid_insn;
929                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
930                         return true;
931                 case INSN_ALU1:
932                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
933                                 goto invalid_insn;
934                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
935                         return true;
936                 case INSN_ROT:
937                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
938                                 goto invalid_insn;
939                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
940                         return true;
941                 case INSN_BTX:
942                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
943                                 goto invalid_insn;
944                         g(cgen_btx(ctx, insn_aux(insn)));
945                         return true;
946                 case INSN_FP_CMP_DEST_REG:
947                         g(cgen_fp_cmp_dest_reg(ctx, insn_op_size(insn), insn_aux(insn)));
948                         return true;
949                 case INSN_FP_ALU:
950                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
951                         return true;
952                 case INSN_FP_ALU1:
953                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
954                         return true;
955                 case INSN_FP_TO_INT32:
956                 case INSN_FP_TO_INT64:
957                         g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
958                         return true;
959                 case INSN_FP_FROM_INT32:
960                 case INSN_FP_FROM_INT64:
961                         g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
962                         return true;
963                 case INSN_JMP:
964                         g(cgen_jmp(ctx, insn_jump_size(insn)));
965                         return true;
966                 case INSN_JMP_REG:
967                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
968                                 goto invalid_insn;
969                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
970                         return true;
971                 case INSN_JMP_2REGS:
972                         if (unlikely(insn_op_size(insn) != OP_SIZE_8))
973                                 goto invalid_insn;
974                         g(cgen_jmp_2regs(ctx, insn_aux(insn), insn_jump_size(insn)));
975                         return true;
976                 case INSN_JMP_INDIRECT:
977                         g(cgen_jmp_call_indirect(ctx, false));
978                         return true;
979                 default:
980                 invalid_insn:
981                         internal(file_line, "cgen_insn: invalid insn %08x in %s", insn, da(ctx->fn,function)->function_name);
982                         return false;
983         }