riscv: Move operand parsing to a separate function
[tinycc.git] / riscv64-asm.c
blobb15bb18278c0d7bcdeb3b65f65c05ad1eca16c3c
1 /*************************************************************/
2 /*
3 * RISCV64 assembler for TCC
5 */
7 #ifdef TARGET_DEFS_ONLY
9 #define CONFIG_TCC_ASM
10 #define NB_ASM_REGS 32
12 ST_FUNC void g(int c);
13 ST_FUNC void gen_le16(int c);
14 ST_FUNC void gen_le32(int c);
16 /*************************************************************/
17 #else
18 /*************************************************************/
19 #define USING_GLOBALS
20 #include "tcc.h"
22 enum {
23 OPT_REG,
24 OPT_IM12S,
25 OPT_IM32,
27 #define C_ENCODE_RS1(register_index) ((register_index) << 7)
28 #define C_ENCODE_RS2(register_index) ((register_index) << 2)
29 #define ENCODE_RD(register_index) ((register_index) << 7)
30 #define ENCODE_RS1(register_index) ((register_index) << 15)
31 #define ENCODE_RS2(register_index) ((register_index) << 20)
32 #define NTH_BIT(b, n) ((b >> n) & 1)
33 #define OP_IM12S (1 << OPT_IM12S)
34 #define OP_IM32 (1 << OPT_IM32)
35 #define OP_REG (1 << OPT_REG)
37 typedef struct Operand {
38 uint32_t type;
39 union {
40 uint8_t reg;
41 uint16_t regset;
42 ExprValue e;
44 } Operand;
46 static void asm_binary_opcode(TCCState* s1, int token);
47 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str);
48 ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);
49 static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
50 static void asm_emit_i(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
51 static void asm_emit_j(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
52 static void asm_emit_opcode(uint32_t opcode);
53 static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
54 static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
55 static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
56 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
57 static void asm_nullary_opcode(TCCState *s1, int token);
58 ST_FUNC void asm_opcode(TCCState *s1, int token);
59 static int asm_parse_csrvar(int t);
60 ST_FUNC int asm_parse_regvar(int t);
61 static void asm_ternary_opcode(TCCState *s1, int token);
62 static void asm_unary_opcode(TCCState *s1, int token);
63 ST_FUNC void gen_expr32(ExprValue *pe);
64 static void parse_operand(TCCState *s1, Operand *op);
65 static void parse_operands(TCCState *s1, Operand *ops, int count);
66 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
67 /* C extension */
68 static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
69 static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm);
70 static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
71 static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
72 static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm);
73 static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm);
74 static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
75 static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm);
76 static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm);
78 /* XXX: make it faster ? */
79 ST_FUNC void g(int c)
81 int ind1;
82 if (nocode_wanted)
83 return;
84 ind1 = ind + 1;
85 if (ind1 > cur_text_section->data_allocated)
86 section_realloc(cur_text_section, ind1);
87 cur_text_section->data[ind] = c;
88 ind = ind1;
91 ST_FUNC void gen_le16 (int i)
93 g(i);
94 g(i>>8);
97 ST_FUNC void gen_le32 (int i)
99 int ind1;
100 if (nocode_wanted)
101 return;
102 ind1 = ind + 4;
103 if (ind1 > cur_text_section->data_allocated)
104 section_realloc(cur_text_section, ind1);
105 cur_text_section->data[ind++] = i & 0xFF;
106 cur_text_section->data[ind++] = (i >> 8) & 0xFF;
107 cur_text_section->data[ind++] = (i >> 16) & 0xFF;
108 cur_text_section->data[ind++] = (i >> 24) & 0xFF;
111 ST_FUNC void gen_expr32(ExprValue *pe)
113 gen_le32(pe->v);
116 static void asm_emit_opcode(uint32_t opcode) {
117 gen_le32(opcode);
120 static void asm_nullary_opcode(TCCState *s1, int token)
122 static const Operand nil = {.type = OP_REG};
123 static const Operand zimm = {.type = OP_IM12S};
125 switch (token) {
126 // Sync instructions
128 case TOK_ASM_fence: // I
129 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
130 return;
131 case TOK_ASM_fence_i: // I
132 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
133 return;
135 // System calls
137 case TOK_ASM_ecall: // I (pseudo)
138 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
139 return;
140 case TOK_ASM_ebreak: // I (pseudo)
141 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
142 return;
144 // Other
146 case TOK_ASM_nop:
147 asm_emit_i(token, (4 << 2) | 3, &nil, &nil, &zimm);
148 return;
150 case TOK_ASM_wfi:
151 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
152 return;
154 /* C extension */
155 case TOK_ASM_c_ebreak:
156 asm_emit_cr(token, 2 | (9 << 12), &nil, &nil);
157 return;
158 case TOK_ASM_c_nop:
159 asm_emit_ci(token, 1, &nil, &zimm);
160 return;
162 default:
163 expect("nullary instruction");
167 /* Parse a text containing operand and store the result in OP */
168 static void parse_operand(TCCState *s1, Operand *op)
170 ExprValue e = {0};
171 Sym label = {0};
172 int8_t reg;
174 op->type = 0;
176 if ((reg = asm_parse_regvar(tok)) != -1) {
177 next(); // skip register name
178 op->type = OP_REG;
179 op->reg = (uint8_t) reg;
180 return;
181 } else if (tok == '$') {
182 /* constant value */
183 next(); // skip '#' or '$'
184 } else if ((e.v = asm_parse_csrvar(tok)) != -1) {
185 next();
186 } else {
187 asm_expr(s1, &e);
189 op->type = OP_IM32;
190 op->e = e;
191 /* compare against unsigned 12-bit maximum */
192 if (!op->e.sym) {
193 if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000)
194 op->type = OP_IM12S;
195 } else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) {
196 label.type.t = VT_VOID | VT_STATIC;
198 /* use the medium PIC model: GOT, auipc, lw */
199 if (op->e.sym->type.t & VT_STATIC)
200 greloca(cur_text_section, op->e.sym, ind, R_RISCV_PCREL_HI20, 0);
201 else
202 greloca(cur_text_section, op->e.sym, ind, R_RISCV_GOT_HI20, 0);
203 put_extern_sym(&label, cur_text_section, ind, 0);
204 greloca(cur_text_section, &label, ind+4, R_RISCV_PCREL_LO12_I, 0);
206 op->type = OP_IM12S;
207 op->e.v = 0;
208 } else {
209 expect("operand");
213 static void parse_operands(TCCState *s1, Operand* ops, int count){
214 int i;
215 for (i = 0; i < count; i++) {
216 if ( i != 0 ) {
217 if ( tok == ',')
218 next();
219 else
220 expect("','");
222 parse_operand(s1, &ops[i]);
226 static void asm_unary_opcode(TCCState *s1, int token)
228 uint32_t opcode = (0x1C << 2) | 3 | (2 << 12);
229 Operand op;
230 static const Operand nil = {.type = OP_REG};
232 parse_operands(s1, &op, 1);
233 /* Note: Those all map to CSR--so they are pseudo-instructions. */
234 opcode |= ENCODE_RD(op.reg);
236 switch (token) {
237 /* pseudoinstructions */
238 case TOK_ASM_rdcycle:
239 asm_emit_opcode(opcode | (0xC00 << 20));
240 return;
241 case TOK_ASM_rdcycleh:
242 asm_emit_opcode(opcode | (0xC80 << 20));
243 return;
244 case TOK_ASM_rdtime:
245 asm_emit_opcode(opcode | (0xC01 << 20) | ENCODE_RD(op.reg));
246 return;
247 case TOK_ASM_rdtimeh:
248 asm_emit_opcode(opcode | (0xC81 << 20) | ENCODE_RD(op.reg));
249 return;
250 case TOK_ASM_rdinstret:
251 asm_emit_opcode(opcode | (0xC02 << 20) | ENCODE_RD(op.reg));
252 return;
253 case TOK_ASM_rdinstreth:
254 asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
255 return;
256 /* C extension */
257 case TOK_ASM_c_j:
258 asm_emit_cj(token, 1 | (5 << 13), &op);
259 return;
260 case TOK_ASM_c_jal: /* RV32C-only */
261 asm_emit_cj(token, 1 | (1 << 13), &op);
262 return;
263 case TOK_ASM_c_jalr:
264 asm_emit_cr(token, 2 | (9 << 12), &op, &nil);
265 return;
266 case TOK_ASM_c_jr:
267 asm_emit_cr(token, 2 | (8 << 12), &op, &nil);
268 return;
269 default:
270 expect("unary instruction");
274 static void asm_emit_u(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
276 if (rd->type != OP_REG) {
277 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
278 return;
280 if (rs2->type != OP_IM12S && rs2->type != OP_IM32) {
281 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token, NULL));
282 return;
283 } else if (rs2->e.v >= 0x100000) {
284 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0xfffff", get_tok_str(token, NULL));
285 return;
287 /* U-type instruction:
288 31...12 imm[31:12]
289 11...7 rd
290 6...0 opcode */
291 gen_le32(opcode | ENCODE_RD(rd->reg) | (rs2->e.v << 12));
294 static void asm_binary_opcode(TCCState* s1, int token)
296 Operand ops[2];
297 parse_operands(s1, &ops[0], 2);
299 switch (token) {
300 case TOK_ASM_lui:
301 asm_emit_u(token, (0xD << 2) | 3, &ops[0], &ops[1]);
302 return;
303 case TOK_ASM_auipc:
304 asm_emit_u(token, (0x05 << 2) | 3, &ops[0], &ops[1]);
305 return;
306 case TOK_ASM_jal:
307 asm_emit_j(token, 0x6f, ops, ops + 1);
308 return;
310 /* C extension */
311 case TOK_ASM_c_add:
312 asm_emit_cr(token, 2 | (9 << 12), ops, ops + 1);
313 return;
314 case TOK_ASM_c_mv:
315 asm_emit_cr(token, 2 | (8 << 12), ops, ops + 1);
316 return;
318 case TOK_ASM_c_addi16sp:
319 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
320 return;
321 case TOK_ASM_c_addi:
322 asm_emit_ci(token, 1, ops, ops + 1);
323 return;
324 case TOK_ASM_c_addiw:
325 asm_emit_ci(token, 1 | (1 << 13), ops, ops + 1);
326 return;
327 case TOK_ASM_c_fldsp:
328 asm_emit_ci(token, 2 | (1 << 13), ops, ops + 1);
329 return;
330 case TOK_ASM_c_flwsp: /* RV32FC-only */
331 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
332 return;
333 case TOK_ASM_c_ldsp:
334 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
335 return;
336 case TOK_ASM_c_li:
337 asm_emit_ci(token, 1 | (2 << 13), ops, ops + 1);
338 return;
339 case TOK_ASM_c_lui:
340 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
341 return;
342 case TOK_ASM_c_lwsp:
343 asm_emit_ci(token, 2 | (2 << 13), ops, ops + 1);
344 return;
345 case TOK_ASM_c_slli:
346 asm_emit_ci(token, 2, ops, ops + 1);
347 return;
349 case TOK_ASM_c_addi4spn:
350 asm_emit_ciw(token, 0, ops, ops + 1);
351 return;
353 #define CA (1 | (3 << 10) | (4 << 13))
354 case TOK_ASM_c_addw:
355 asm_emit_ca(token, CA | (1 << 5) | (1 << 12), ops, ops + 1);
356 return;
357 case TOK_ASM_c_and:
358 asm_emit_ca(token, CA | (3 << 5), ops, ops + 1);
359 return;
360 case TOK_ASM_c_or:
361 asm_emit_ca(token, CA | (2 << 5), ops, ops + 1);
362 return;
363 case TOK_ASM_c_sub:
364 asm_emit_ca(token, CA, ops, ops + 1);
365 return;
366 case TOK_ASM_c_subw:
367 asm_emit_ca(token, CA | (1 << 12), ops, ops + 1);
368 return;
369 case TOK_ASM_c_xor:
370 asm_emit_ca(token, CA | (1 << 5), ops, ops + 1);
371 return;
372 #undef CA
374 case TOK_ASM_c_andi:
375 asm_emit_cb(token, 1 | (2 << 10) | (4 << 13), ops, ops + 1);
376 return;
377 case TOK_ASM_c_beqz:
378 asm_emit_cb(token, 1 | (6 << 13), ops, ops + 1);
379 return;
380 case TOK_ASM_c_bnez:
381 asm_emit_cb(token, 1 | (7 << 13), ops, ops + 1);
382 return;
383 case TOK_ASM_c_srai:
384 asm_emit_cb(token, 1 | (1 << 10) | (4 << 13), ops, ops + 1);
385 return;
386 case TOK_ASM_c_srli:
387 asm_emit_cb(token, 1 | (4 << 13), ops, ops + 1);
388 return;
390 case TOK_ASM_c_sdsp:
391 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
392 return;
393 case TOK_ASM_c_swsp:
394 asm_emit_css(token, 2 | (6 << 13), ops, ops + 1);
395 return;
396 case TOK_ASM_c_fswsp: /* RV32FC-only */
397 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
398 return;
399 case TOK_ASM_c_fsdsp:
400 asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
401 return;
403 /* pseudoinstructions */
404 /* rd, sym */
405 case TOK_ASM_la:
406 /* auipc rd, 0 */
407 asm_emit_u(token, 3 | (5 << 2), ops, ops + 1);
408 /* lw rd, rd, 0 */
409 asm_emit_i(token, 3 | (2 << 12), ops, ops, ops + 1);
410 return;
411 case TOK_ASM_lla:
412 /* auipc rd, 0 */
413 asm_emit_u(token, 3 | (5 << 2), ops, ops + 1);
414 /* addi rd, rd, 0 */
415 asm_emit_i(token, 3 | (4 << 2), ops, ops, ops + 1);
416 return;
418 default:
419 expect("binary instruction");
423 /* caller: Add funct3, funct7 into opcode */
424 static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
426 if (rd->type != OP_REG) {
427 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
428 return;
430 if (rs1->type != OP_REG) {
431 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
432 return;
434 if (rs2->type != OP_REG) {
435 tcc_error("'%s': Expected second source operand that is a register or immediate", get_tok_str(token, NULL));
436 return;
438 /* R-type instruction:
439 31...25 funct7
440 24...20 rs2
441 19...15 rs1
442 14...12 funct3
443 11...7 rd
444 6...0 opcode */
445 gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
448 /* caller: Add funct3 into opcode */
449 static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
451 if (rd->type != OP_REG) {
452 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
453 return;
455 if (rs1->type != OP_REG) {
456 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
457 return;
459 if (rs2->type != OP_IM12S) {
460 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
461 return;
463 /* I-type instruction:
464 31...20 imm[11:0]
465 19...15 rs1
466 14...12 funct3
467 11...7 rd
468 6...0 opcode */
470 gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | (rs2->e.v << 20));
473 static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
475 uint32_t imm;
477 if (rd->type != OP_REG) {
478 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
479 return;
481 if (rs2->type != OP_IM12S && rs2->type != OP_IM32) {
482 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token, NULL));
483 return;
486 imm = rs2->e.v;
488 /* even offsets in a +- 1 MiB range */
489 if (imm > 0x1ffffe) {
490 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0x1fffff", get_tok_str(token, NULL));
491 return;
494 if (imm & 1) {
495 tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token, NULL));
496 return;
498 /* J-type instruction:
499 31 imm[20]
500 30...21 imm[10:1]
501 20 imm[11]
502 19...12 imm[19:12]
503 11...7 rd
504 6...0 opcode */
505 gen_le32(opcode | ENCODE_RD(rd->reg) | (((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3ff) << 21) | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xff) << 12));
508 static void asm_ternary_opcode(TCCState *s1, int token)
510 Operand ops[3];
511 parse_operands(s1, &ops[0], 3);
513 switch (token) {
514 case TOK_ASM_sll:
515 asm_emit_r(token, (0xC << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
516 return;
517 case TOK_ASM_slli:
518 asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
519 return;
520 case TOK_ASM_srl:
521 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
522 return;
523 case TOK_ASM_srli:
524 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
525 return;
526 case TOK_ASM_sra:
527 asm_emit_r(token, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
528 return;
529 case TOK_ASM_srai:
530 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops[0], &ops[1], &ops[2]);
531 return;
532 case TOK_ASM_sllw:
533 asm_emit_r(token, (0xE << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
534 return;
535 case TOK_ASM_slliw:
536 asm_emit_i(token, (6 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
537 return;
538 case TOK_ASM_srlw:
539 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
540 return;
541 case TOK_ASM_srliw:
542 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
543 return;
544 case TOK_ASM_sraw:
545 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
546 return;
547 case TOK_ASM_sraiw:
548 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
549 return;
551 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
553 case TOK_ASM_add:
554 asm_emit_r(token, (0xC << 2) | 3, &ops[0], &ops[1], &ops[2]);
555 return;
556 case TOK_ASM_addi:
557 asm_emit_i(token, (4 << 2) | 3, &ops[0], &ops[1], &ops[2]);
558 return;
559 case TOK_ASM_sub:
560 asm_emit_r(token, (0xC << 2) | 3 | (32 << 25), &ops[0], &ops[1], &ops[2]);
561 return;
562 case TOK_ASM_addw:
563 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
564 return;
565 case TOK_ASM_addiw: // 64 bit
566 asm_emit_i(token, (0x6 << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
567 return;
568 case TOK_ASM_subw:
569 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
570 return;
572 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
574 case TOK_ASM_xor:
575 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
576 return;
577 case TOK_ASM_xori:
578 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
579 return;
580 case TOK_ASM_or:
581 asm_emit_r(token, (0xC << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
582 return;
583 case TOK_ASM_ori:
584 asm_emit_i(token, (0x4 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
585 return;
586 case TOK_ASM_and:
587 asm_emit_r(token, (0xC << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
588 return;
589 case TOK_ASM_andi:
590 asm_emit_i(token, (0x4 << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
591 return;
593 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
595 case TOK_ASM_slt:
596 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
597 return;
598 case TOK_ASM_slti:
599 asm_emit_i(token, (0x4 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
600 return;
601 case TOK_ASM_sltu:
602 asm_emit_r(token, (0xC << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
603 return;
604 case TOK_ASM_sltiu:
605 asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
606 return;
608 /* indirect jump (RD, RS1, IMM); I-format */
609 case TOK_ASM_jalr:
610 asm_emit_i(token, 0x67 | (0 << 12), ops, ops + 1, ops + 2);
611 return;
613 /* branch (RS1, RS2, IMM); B-format */
614 case TOK_ASM_beq:
615 asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2);
616 return;
617 case TOK_ASM_bne:
618 asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2);
619 return;
620 case TOK_ASM_blt:
621 asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2);
622 return;
623 case TOK_ASM_bge:
624 asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2);
625 return;
626 case TOK_ASM_bltu:
627 asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2);
628 return;
629 case TOK_ASM_bgeu:
630 asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2);
631 return;
633 // Loads (RD,RS1,I); I-format
635 case TOK_ASM_lb:
636 asm_emit_i(token, (0x0 << 2) | 3, &ops[0], &ops[1], &ops[2]);
637 return;
638 case TOK_ASM_lh:
639 asm_emit_i(token, (0x0 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
640 return;
641 case TOK_ASM_lw:
642 asm_emit_i(token, (0x0 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
643 return;
644 case TOK_ASM_lbu:
645 asm_emit_i(token, (0x0 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
646 return;
647 case TOK_ASM_lhu:
648 asm_emit_i(token, (0x0 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
649 return;
650 // 64 bit
651 case TOK_ASM_ld:
652 asm_emit_i(token, (0x0 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
653 return;
654 case TOK_ASM_lwu:
655 asm_emit_i(token, (0x0 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
656 return;
658 // Stores (RS1,RS2,I); S-format
660 case TOK_ASM_sb:
661 asm_emit_s(token, (0x8 << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
662 return;
663 case TOK_ASM_sh:
664 asm_emit_s(token, (0x8 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
665 return;
666 case TOK_ASM_sw:
667 asm_emit_s(token, (0x8 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
668 return;
669 case TOK_ASM_sd:
670 asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
671 return;
673 /* M extension */
674 case TOK_ASM_div:
675 asm_emit_r(token, 0x33 | (4 << 12) | (1 << 25), ops, ops + 1, ops + 2);
676 return;
677 case TOK_ASM_divu:
678 asm_emit_r(token, 0x33 | (5 << 12) | (1 << 25), ops, ops + 1, ops + 2);
679 return;
680 case TOK_ASM_divuw:
681 asm_emit_r(token, 0x3b | (5 << 12) | (1 << 25), ops, ops + 1, ops + 2);
682 return;
683 case TOK_ASM_divw:
684 asm_emit_r(token, 0x3b | (4 << 12) | (1 << 25), ops, ops + 1, ops + 2);
685 return;
686 case TOK_ASM_mul:
687 asm_emit_r(token, 0x33 | (1 << 25), ops, ops + 1, ops + 2);
688 return;
689 case TOK_ASM_mulh:
690 asm_emit_r(token, 0x33 | (1 << 12) | (1 << 25), ops, ops + 1, ops + 2);
691 return;
692 case TOK_ASM_mulhsu:
693 asm_emit_r(token, 0x33 | (2 << 12) | (1 << 25), ops, ops + 1, ops + 2);
694 return;
695 case TOK_ASM_mulhu:
696 asm_emit_r(token, 0x33 | (3 << 12) | (1 << 25), ops, ops + 1, ops + 2);
697 return;
698 case TOK_ASM_mulw:
699 asm_emit_r(token, 0x3b | (1 << 25), ops, ops + 1, ops + 2);
700 return;
701 case TOK_ASM_rem:
702 asm_emit_r(token, 0x33 | (6 << 12) | (1 << 25), ops, ops + 1, ops + 2);
703 return;
704 case TOK_ASM_remu:
705 asm_emit_r(token, 0x33 | (7 << 12) | (1 << 25), ops, ops + 1, ops + 2);
706 return;
707 case TOK_ASM_remuw:
708 asm_emit_r(token, 0x3b | (7 << 12) | (1 << 25), ops, ops + 1, ops + 2);
709 return;
710 case TOK_ASM_remw:
711 asm_emit_r(token, 0x3b | (6 << 12) | (1 << 25), ops, ops + 1, ops + 2);
712 return;
714 /* Zicsr extension; (rd, csr, rs/uimm) */
715 case TOK_ASM_csrrc:
716 asm_emit_i(token, 0x73 | (3 << 12), ops, ops + 2, ops + 1);
717 return;
718 case TOK_ASM_csrrci:
719 /* using rs1 field for uimmm */
720 ops[2].type = OP_REG;
721 asm_emit_i(token, 0x73 | (7 << 12), ops, ops + 2, ops + 1);
722 return;
723 case TOK_ASM_csrrs:
724 asm_emit_i(token, 0x73 | (2 << 12), ops, ops + 2, ops + 1);
725 return;
726 case TOK_ASM_csrrsi:
727 ops[2].type = OP_REG;
728 asm_emit_i(token, 0x73 | (6 << 12), ops, ops + 2, ops + 1);
729 return;
730 case TOK_ASM_csrrw:
731 asm_emit_i(token, 0x73 | (1 << 12), ops, ops + 2, ops + 1);
732 return;
733 case TOK_ASM_csrrwi:
734 ops[2].type = OP_REG;
735 asm_emit_i(token, 0x73 | (5 << 12), ops, ops + 2, ops + 1);
736 return;
738 /* C extension */
739 /* register-based loads and stores (RD, RS1, IMM); CL-format */
740 case TOK_ASM_c_fld:
741 asm_emit_cl(token, 1 << 13, ops, ops + 1, ops + 2);
742 return;
743 case TOK_ASM_c_flw: /* RV32FC-only */
744 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
745 return;
746 case TOK_ASM_c_fsd:
747 asm_emit_cs(token, 5 << 13, ops, ops + 1, ops + 2);
748 return;
749 case TOK_ASM_c_fsw: /* RV32FC-only */
750 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
751 return;
752 case TOK_ASM_c_ld:
753 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
754 return;
755 case TOK_ASM_c_lw:
756 asm_emit_cl(token, 2 << 13, ops, ops + 1, ops + 2);
757 return;
758 case TOK_ASM_c_sd:
759 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
760 return;
761 case TOK_ASM_c_sw:
762 asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
763 return;
765 default:
766 expect("ternary instruction");
770 /* caller: Add funct3 to opcode */
771 static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
773 if (rs1->type != OP_REG) {
774 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
775 return;
777 if (rs2->type != OP_REG) {
778 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
779 return;
781 if (imm->type != OP_IM12S) {
782 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
783 return;
786 uint16_t v = imm->e.v;
787 /* S-type instruction:
788 31...25 imm[11:5]
789 24...20 rs2
790 19...15 rs1
791 14...12 funct3
792 11...7 imm[4:0]
793 6...0 opcode
794 opcode always fixed pos. */
795 gen_le32(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | ((v & 0x1F) << 7) | ((v >> 5) << 25));
799 static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm)
801 uint32_t offset;
803 if (rs1->type != OP_REG) {
804 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
805 return;
807 if (rs2->type != OP_REG) {
808 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
809 return;
811 if (imm->type != OP_IM12S) {
812 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
813 return;
816 offset = imm->e.v;
818 /* B-type instruction:
819 31 imm[12]
820 30...25 imm[10:5]
821 24...20 rs2
822 19...15 rs1
823 14...12 funct3
824 8...11 imm[4:1]
825 7 imm[11]
826 6...0 opcode */
827 asm_emit_opcode(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (((offset >> 1) & 0xF) << 8) | (((offset >> 5) & 0x1f) << 25) | (((offset >> 11) & 1) << 7) | (((offset >> 12) & 1) << 31));
830 ST_FUNC void asm_opcode(TCCState *s1, int token)
832 switch (token) {
833 case TOK_ASM_ebreak:
834 case TOK_ASM_ecall:
835 case TOK_ASM_fence:
836 case TOK_ASM_fence_i:
837 case TOK_ASM_hrts:
838 case TOK_ASM_mrth:
839 case TOK_ASM_mrts:
840 case TOK_ASM_wfi:
841 asm_nullary_opcode(s1, token);
842 return;
844 case TOK_ASM_rdcycle:
845 case TOK_ASM_rdcycleh:
846 case TOK_ASM_rdtime:
847 case TOK_ASM_rdtimeh:
848 case TOK_ASM_rdinstret:
849 case TOK_ASM_rdinstreth:
850 asm_unary_opcode(s1, token);
851 return;
853 case TOK_ASM_lui:
854 case TOK_ASM_auipc:
855 case TOK_ASM_jal:
856 asm_binary_opcode(s1, token);
857 return;
859 case TOK_ASM_add:
860 case TOK_ASM_addi:
861 case TOK_ASM_addiw:
862 case TOK_ASM_addw:
863 case TOK_ASM_and:
864 case TOK_ASM_andi:
865 case TOK_ASM_beq:
866 case TOK_ASM_bge:
867 case TOK_ASM_bgeu:
868 case TOK_ASM_blt:
869 case TOK_ASM_bltu:
870 case TOK_ASM_bne:
871 case TOK_ASM_jalr:
872 case TOK_ASM_lb:
873 case TOK_ASM_lbu:
874 case TOK_ASM_ld:
875 case TOK_ASM_lh:
876 case TOK_ASM_lhu:
877 case TOK_ASM_lw:
878 case TOK_ASM_lwu:
879 case TOK_ASM_or:
880 case TOK_ASM_ori:
881 case TOK_ASM_sb:
882 case TOK_ASM_sd:
883 case TOK_ASM_sh:
884 case TOK_ASM_sll:
885 case TOK_ASM_slli:
886 case TOK_ASM_slliw:
887 case TOK_ASM_sllw:
888 case TOK_ASM_slt:
889 case TOK_ASM_slti:
890 case TOK_ASM_sltiu:
891 case TOK_ASM_sltu:
892 case TOK_ASM_sra:
893 case TOK_ASM_srai:
894 case TOK_ASM_sraiw:
895 case TOK_ASM_sraw:
896 case TOK_ASM_srl:
897 case TOK_ASM_srli:
898 case TOK_ASM_srliw:
899 case TOK_ASM_srlw:
900 case TOK_ASM_sub:
901 case TOK_ASM_subw:
902 case TOK_ASM_sw:
903 case TOK_ASM_xor:
904 case TOK_ASM_xori:
905 /* M extension */
906 case TOK_ASM_div:
907 case TOK_ASM_divu:
908 case TOK_ASM_divuw:
909 case TOK_ASM_divw:
910 case TOK_ASM_mul:
911 case TOK_ASM_mulh:
912 case TOK_ASM_mulhsu:
913 case TOK_ASM_mulhu:
914 case TOK_ASM_mulw:
915 case TOK_ASM_rem:
916 case TOK_ASM_remu:
917 case TOK_ASM_remuw:
918 case TOK_ASM_remw:
919 /* Zicsr extension */
920 case TOK_ASM_csrrc:
921 case TOK_ASM_csrrci:
922 case TOK_ASM_csrrs:
923 case TOK_ASM_csrrsi:
924 case TOK_ASM_csrrw:
925 case TOK_ASM_csrrwi:
926 asm_ternary_opcode(s1, token);
927 return;
929 /* C extension */
930 case TOK_ASM_c_ebreak:
931 case TOK_ASM_c_nop:
932 asm_nullary_opcode(s1, token);
933 return;
935 case TOK_ASM_c_j:
936 case TOK_ASM_c_jal:
937 case TOK_ASM_c_jalr:
938 case TOK_ASM_c_jr:
939 asm_unary_opcode(s1, token);
940 return;
942 case TOK_ASM_c_add:
943 case TOK_ASM_c_addi16sp:
944 case TOK_ASM_c_addi4spn:
945 case TOK_ASM_c_addi:
946 case TOK_ASM_c_addiw:
947 case TOK_ASM_c_addw:
948 case TOK_ASM_c_and:
949 case TOK_ASM_c_andi:
950 case TOK_ASM_c_beqz:
951 case TOK_ASM_c_bnez:
952 case TOK_ASM_c_fldsp:
953 case TOK_ASM_c_flwsp:
954 case TOK_ASM_c_fsdsp:
955 case TOK_ASM_c_fswsp:
956 case TOK_ASM_c_ldsp:
957 case TOK_ASM_c_li:
958 case TOK_ASM_c_lui:
959 case TOK_ASM_c_lwsp:
960 case TOK_ASM_c_mv:
961 case TOK_ASM_c_or:
962 case TOK_ASM_c_sdsp:
963 case TOK_ASM_c_slli:
964 case TOK_ASM_c_srai:
965 case TOK_ASM_c_srli:
966 case TOK_ASM_c_sub:
967 case TOK_ASM_c_subw:
968 case TOK_ASM_c_swsp:
969 case TOK_ASM_c_xor:
970 asm_binary_opcode(s1, token);
971 return;
973 case TOK_ASM_c_fld:
974 case TOK_ASM_c_flw:
975 case TOK_ASM_c_fsd:
976 case TOK_ASM_c_fsw:
977 case TOK_ASM_c_ld:
978 case TOK_ASM_c_lw:
979 case TOK_ASM_c_sd:
980 case TOK_ASM_c_sw:
981 asm_ternary_opcode(s1, token);
982 return;
984 /* pseudoinstructions */
985 case TOK_ASM_nop:
986 asm_nullary_opcode(s1, token);
987 return;
989 case TOK_ASM_la:
990 case TOK_ASM_lla:
991 asm_binary_opcode(s1, token);
992 return;
994 default:
995 expect("known instruction");
999 static int asm_parse_csrvar(int t)
1001 switch (t) {
1002 case TOK_ASM_cycle:
1003 return 0xc00;
1004 case TOK_ASM_fcsr:
1005 return 3;
1006 case TOK_ASM_fflags:
1007 return 1;
1008 case TOK_ASM_frm:
1009 return 2;
1010 case TOK_ASM_instret:
1011 return 0xc02;
1012 case TOK_ASM_time:
1013 return 0xc01;
1014 case TOK_ASM_cycleh:
1015 return 0xc80;
1016 case TOK_ASM_instreth:
1017 return 0xc82;
1018 case TOK_ASM_timeh:
1019 return 0xc81;
1020 default:
1021 return -1;
1025 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
1027 tcc_error("RISCV64 asm not implemented.");
1030 /* generate prolog and epilog code for asm statement */
1031 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
1032 int nb_outputs, int is_output,
1033 uint8_t *clobber_regs,
1034 int out_reg)
1038 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
1039 int nb_operands, int nb_outputs,
1040 const uint8_t *clobber_regs,
1041 int *pout_reg)
1045 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
1047 int reg;
1048 TokenSym *ts;
1050 if (!strcmp(str, "memory") ||
1051 !strcmp(str, "cc") ||
1052 !strcmp(str, "flags"))
1053 return;
1054 ts = tok_alloc(str, strlen(str));
1055 reg = asm_parse_regvar(ts->tok);
1056 if (reg == -1) {
1057 tcc_error("invalid clobber register '%s'", str);
1059 clobber_regs[reg] = 1;
1062 ST_FUNC int asm_parse_regvar (int t)
1064 /* PC register not implemented */
1065 if (t >= TOK_ASM_pc || t < TOK_ASM_x0)
1066 return -1;
1068 if (t < TOK_ASM_f0)
1069 return t - TOK_ASM_x0;
1071 if (t < TOK_ASM_zero)
1072 return t - TOK_ASM_f0;
1074 /* ABI mnemonic */
1075 if (t < TOK_ASM_ft0)
1076 return t - TOK_ASM_zero;
1078 return t - TOK_ASM_ft0;
1081 /*************************************************************/
1082 /* C extension */
1084 /* caller: Add funct6, funct2 into opcode */
1085 static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
1087 uint8_t dst, src;
1089 if (rd->type != OP_REG) {
1090 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1091 return;
1094 if (rs2->type != OP_REG) {
1095 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1096 return;
1099 /* subtract index of x8 */
1100 dst = rd->reg - 8;
1101 src = rs2->reg - 8;
1103 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
1104 if (dst > 7) {
1105 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1106 return;
1109 if (src > 7) {
1110 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1111 return;
1114 /* CA-type instruction:
1115 15...10 funct6
1116 9...7 rd'/rs1'
1117 6..5 funct2
1118 4...2 rs2'
1119 1...0 opcode */
1121 gen_le16(opcode | C_ENCODE_RS2(src) | C_ENCODE_RS1(dst));
1124 static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm)
1126 uint32_t offset;
1127 uint8_t src;
1129 if (rs1->type != OP_REG) {
1130 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1131 return;
1134 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1135 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1136 return;
1139 offset = imm->e.v;
1141 if (offset & 1) {
1142 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
1143 return;
1146 src = rs1->reg - 8;
1148 if (src > 7) {
1149 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1150 return;
1153 /* CB-type instruction:
1154 15...13 funct3
1155 12...10 offset
1156 9..7 rs1'
1157 6...2 offset
1158 1...0 opcode */
1160 /* non-branch also using CB:
1161 15...13 funct3
1162 12 imm
1163 11..10 funct2
1164 9...7 rd'/rs1'
1165 6..2 imm
1166 1...0 opcode */
1168 switch (token) {
1169 case TOK_ASM_c_beqz:
1170 case TOK_ASM_c_bnez:
1171 gen_le16(opcode | C_ENCODE_RS1(src) | ((NTH_BIT(offset, 5) | (((offset >> 1) & 3) << 1) | (((offset >> 6) & 3) << 3)) << 2) | ((((offset >> 3) & 3) | NTH_BIT(offset, 8)) << 10));
1172 return;
1173 default:
1174 gen_le16(opcode | C_ENCODE_RS1(src) | ((offset & 0x1f) << 2) | (NTH_BIT(offset, 5) << 12));
1175 return;
1179 static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
1181 uint32_t immediate;
1183 if (rd->type != OP_REG) {
1184 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1185 return;
1188 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1189 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1190 return;
1193 immediate = imm->e.v;
1195 /* CI-type instruction:
1196 15...13 funct3
1197 12 imm
1198 11...7 rd/rs1
1199 6...2 imm
1200 1...0 opcode */
1202 switch (token) {
1203 case TOK_ASM_c_addi:
1204 case TOK_ASM_c_addiw:
1205 case TOK_ASM_c_li:
1206 case TOK_ASM_c_slli:
1207 gen_le16(opcode | ((immediate & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1208 return;
1209 case TOK_ASM_c_addi16sp:
1210 gen_le16(opcode | NTH_BIT(immediate, 5) << 2 | (((immediate >> 7) & 3) << 3) | NTH_BIT(immediate, 6) << 5 | NTH_BIT(immediate, 4) << 6 | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 9) << 12));
1211 return;
1212 case TOK_ASM_c_lui:
1213 gen_le16(opcode | (((immediate >> 12) & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 17) << 12));
1214 return;
1215 case TOK_ASM_c_fldsp:
1216 case TOK_ASM_c_ldsp:
1217 gen_le16(opcode | (((immediate >> 6) & 7) << 2) | (((immediate >> 3) & 2) << 5) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1218 return;
1219 case TOK_ASM_c_flwsp:
1220 case TOK_ASM_c_lwsp:
1221 gen_le16(opcode | (((immediate >> 6) & 3) << 2) | (((immediate >> 2) & 7) << 4) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1222 return;
1223 case TOK_ASM_c_nop:
1224 gen_le16(opcode);
1225 return;
1226 default:
1227 expect("known instruction");
1231 /* caller: Add funct3 into opcode */
1232 static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
1234 uint32_t nzuimm;
1235 uint8_t dst;
1237 if (rd->type != OP_REG) {
1238 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1239 return;
1242 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1243 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1244 return;
1247 dst = rd->reg - 8;
1249 if (dst > 7) {
1250 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1251 return;
1254 nzuimm = imm->e.v;
1256 if (nzuimm > 0x3fc) {
1257 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x3ff", get_tok_str(token, NULL));
1258 return;
1261 if (nzuimm & 3) {
1262 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token, NULL));
1263 return;
1266 /* CIW-type instruction:
1267 15...13 funct3
1268 12...5 imm
1269 4...2 rd'
1270 1...0 opcode */
1272 gen_le16(opcode | ENCODE_RS2(rd->reg) | ((NTH_BIT(nzuimm, 3) | (NTH_BIT(nzuimm, 2) << 1) | (((nzuimm >> 6) & 0xf) << 2) | (((nzuimm >> 4) & 3) << 6)) << 5));
1275 /* caller: Add funct3 into opcode */
1276 static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm)
1278 uint32_t offset;
1280 /* +-2 KiB range */
1281 if (imm->type != OP_IM12S) {
1282 tcc_error("'%s': Expected source operand that is a 12-bit immediate value", get_tok_str(token, NULL));
1283 return;
1286 offset = imm->e.v;
1288 if (offset & 1) {
1289 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
1290 return;
1293 /* CJ-type instruction:
1294 15...13 funct3
1295 12...2 offset[11|4|9:8|10|6|7|3:1|5]
1296 1...0 opcode */
1298 gen_le16(opcode | (NTH_BIT(offset, 5) << 2) | (((offset >> 1) & 7) << 3) | (NTH_BIT(offset, 7) << 6) | (NTH_BIT(offset, 6) << 7) | (NTH_BIT(offset, 10) << 8) | (((offset >> 8) & 3) << 9) | (NTH_BIT(offset, 4) << 11) | (NTH_BIT(offset, 11) << 12));
1301 /* caller: Add funct3 into opcode */
1302 static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm)
1304 uint32_t offset;
1305 uint8_t dst, src;
1307 if (rd->type != OP_REG) {
1308 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1309 return;
1312 if (rs1->type != OP_REG) {
1313 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1314 return;
1317 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1318 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1319 return;
1322 dst = rd->reg - 8;
1323 src = rs1->reg - 8;
1325 if (dst > 7) {
1326 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1327 return;
1330 if (src > 7) {
1331 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1332 return;
1335 offset = imm->e.v;
1337 if (offset > 0xff) {
1338 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1339 return;
1342 if (offset & 3) {
1343 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1344 return;
1347 /* CL-type instruction:
1348 15...13 funct3
1349 12...10 imm
1350 9...7 rs1'
1351 6...5 imm
1352 4...2 rd'
1353 1...0 opcode */
1355 switch (token) {
1356 /* imm variant 1 */
1357 case TOK_ASM_c_flw:
1358 case TOK_ASM_c_lw:
1359 gen_le16(opcode | C_ENCODE_RS2(dst) | C_ENCODE_RS1(src) | (NTH_BIT(offset, 6) << 5) | (NTH_BIT(offset, 2) << 6) | (((offset >> 3) & 7) << 10));
1360 return;
1361 /* imm variant 2 */
1362 case TOK_ASM_c_fld:
1363 case TOK_ASM_c_ld:
1364 gen_le16(opcode | C_ENCODE_RS2(dst) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
1365 return;
1366 default:
1367 expect("known instruction");
1371 /* caller: Add funct4 into opcode */
1372 static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
1374 if (rd->type != OP_REG) {
1375 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1376 return;
1379 if (rs2->type != OP_REG) {
1380 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1381 return;
1384 /* CR-type instruction:
1385 15...12 funct4
1386 11..7 rd/rs1
1387 6...2 rs2
1388 1...0 opcode */
1390 gen_le16(opcode | C_ENCODE_RS1(rd->reg) | C_ENCODE_RS2(rs2->reg));
1393 /* caller: Add funct3 into opcode */
1394 static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm)
1396 uint32_t offset;
1397 uint8_t base, src;
1399 if (rs2->type != OP_REG) {
1400 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1401 return;
1404 if (rs1->type != OP_REG) {
1405 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1406 return;
1409 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1410 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1411 return;
1414 base = rs1->reg - 8;
1415 src = rs2->reg - 8;
1417 if (base > 7) {
1418 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1419 return;
1422 if (src > 7) {
1423 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1424 return;
1427 offset = imm->e.v;
1429 if (offset > 0xff) {
1430 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1431 return;
1434 if (offset & 3) {
1435 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1436 return;
1439 /* CS-type instruction:
1440 15...13 funct3
1441 12...10 imm
1442 9...7 rs1'
1443 6...5 imm
1444 4...2 rs2'
1445 1...0 opcode */
1446 switch (token) {
1447 /* imm variant 1 */
1448 case TOK_ASM_c_fsw:
1449 case TOK_ASM_c_sw:
1450 gen_le16(opcode | C_ENCODE_RS2(base) | C_ENCODE_RS1(src) | (NTH_BIT(offset, 6) << 5) | (NTH_BIT(offset, 2) << 6) | (((offset >> 3) & 7) << 10));
1451 return;
1452 /* imm variant 2 */
1453 case TOK_ASM_c_fsd:
1454 case TOK_ASM_c_sd:
1455 gen_le16(opcode | C_ENCODE_RS2(base) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
1456 return;
1457 default:
1458 expect("known instruction");
1462 /* caller: Add funct3 into opcode */
1463 static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm)
1465 uint32_t offset;
1467 if (rs2->type != OP_REG) {
1468 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1469 return;
1472 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1473 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1474 return;
1477 offset = imm->e.v;
1479 if (offset > 0xff) {
1480 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1481 return;
1484 if (offset & 3) {
1485 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1486 return;
1489 /* CSS-type instruction:
1490 15...13 funct3
1491 12...7 imm
1492 6...2 rs2
1493 1...0 opcode */
1495 switch (token) {
1496 /* imm variant 1 */
1497 case TOK_ASM_c_fswsp:
1498 case TOK_ASM_c_swsp:
1499 gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 3) << 7) | (((offset >> 2) & 0xf) << 9));
1500 return;
1501 /* imm variant 2 */
1502 case TOK_ASM_c_fsdsp:
1503 case TOK_ASM_c_sdsp:
1504 gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 7) << 7) | (((offset >> 3) & 7) << 10));
1505 return;
1506 default:
1507 expect("known instruction");
1511 /*************************************************************/
1512 #endif /* ndef TARGET_DEFS_ONLY */