riscv: Support $ in identifiers in extended asm.
[tinycc.git] / riscv64-asm.c
blob11a488aef306947c057c3e3bebab34c5000f6bcb
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 static void parse_mem_access_operands(TCCState *s1, Operand* ops);
67 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
68 /* C extension */
69 static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
70 static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm);
71 static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
72 static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
73 static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm);
74 static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm);
75 static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
76 static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm);
77 static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm);
79 /* XXX: make it faster ? */
80 ST_FUNC void g(int c)
82 int ind1;
83 if (nocode_wanted)
84 return;
85 ind1 = ind + 1;
86 if (ind1 > cur_text_section->data_allocated)
87 section_realloc(cur_text_section, ind1);
88 cur_text_section->data[ind] = c;
89 ind = ind1;
92 ST_FUNC void gen_le16 (int i)
94 g(i);
95 g(i>>8);
98 ST_FUNC void gen_le32 (int i)
100 int ind1;
101 if (nocode_wanted)
102 return;
103 ind1 = ind + 4;
104 if (ind1 > cur_text_section->data_allocated)
105 section_realloc(cur_text_section, ind1);
106 cur_text_section->data[ind++] = i & 0xFF;
107 cur_text_section->data[ind++] = (i >> 8) & 0xFF;
108 cur_text_section->data[ind++] = (i >> 16) & 0xFF;
109 cur_text_section->data[ind++] = (i >> 24) & 0xFF;
112 ST_FUNC void gen_expr32(ExprValue *pe)
114 gen_le32(pe->v);
117 static void asm_emit_opcode(uint32_t opcode) {
118 gen_le32(opcode);
121 static void asm_nullary_opcode(TCCState *s1, int token)
123 static const Operand nil = {.type = OP_REG};
124 static const Operand zimm = {.type = OP_IM12S};
126 switch (token) {
127 // Sync instructions
129 case TOK_ASM_fence: // I
130 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
131 return;
132 case TOK_ASM_fence_i: // I
133 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
134 return;
136 // System calls
138 case TOK_ASM_ecall: // I (pseudo)
139 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
140 return;
141 case TOK_ASM_ebreak: // I (pseudo)
142 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
143 return;
145 // Other
147 case TOK_ASM_nop:
148 asm_emit_i(token, (4 << 2) | 3, &nil, &nil, &zimm);
149 return;
151 case TOK_ASM_wfi:
152 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
153 return;
155 /* Pseudoinstructions */
156 case TOK_ASM_ret:
157 /* jalr zero, x1, 0 */
158 asm_emit_opcode( 0x67 | (0 << 12) | ENCODE_RS1(1) );
159 return;
161 /* C extension */
162 case TOK_ASM_c_ebreak:
163 asm_emit_cr(token, 2 | (9 << 12), &nil, &nil);
164 return;
165 case TOK_ASM_c_nop:
166 asm_emit_ci(token, 1, &nil, &zimm);
167 return;
169 default:
170 expect("nullary instruction");
174 /* Parse a text containing operand and store the result in OP */
175 static void parse_operand(TCCState *s1, Operand *op)
177 ExprValue e = {0};
178 Sym label = {0};
179 int8_t reg;
181 op->type = 0;
183 if ((reg = asm_parse_regvar(tok)) != -1) {
184 next(); // skip register name
185 op->type = OP_REG;
186 op->reg = (uint8_t) reg;
187 return;
188 } else if (tok == '$') {
189 /* constant value */
190 next(); // skip '#' or '$'
191 } else if ((e.v = asm_parse_csrvar(tok)) != -1) {
192 next();
193 } else {
194 asm_expr(s1, &e);
196 op->type = OP_IM32;
197 op->e = e;
198 /* compare against unsigned 12-bit maximum */
199 if (!op->e.sym) {
200 if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000)
201 op->type = OP_IM12S;
202 } else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) {
203 label.type.t = VT_VOID | VT_STATIC;
205 /* use the medium PIC model: GOT, auipc, lw */
206 if (op->e.sym->type.t & VT_STATIC)
207 greloca(cur_text_section, op->e.sym, ind, R_RISCV_PCREL_HI20, 0);
208 else
209 greloca(cur_text_section, op->e.sym, ind, R_RISCV_GOT_HI20, 0);
210 put_extern_sym(&label, cur_text_section, ind, 0);
211 greloca(cur_text_section, &label, ind+4, R_RISCV_PCREL_LO12_I, 0);
213 op->type = OP_IM12S;
214 op->e.v = 0;
215 } else {
216 expect("operand");
220 static void parse_operands(TCCState *s1, Operand* ops, int count){
221 int i;
222 for (i = 0; i < count; i++) {
223 if ( i != 0 ) {
224 if ( tok == ',')
225 next();
226 else
227 expect("','");
229 parse_operand(s1, &ops[i]);
233 /* parse `X, imm(Y)` to {X, Y, imm} operands */
234 static void parse_mem_access_operands(TCCState *s1, Operand* ops){
235 static const Operand zimm = {.type = OP_IM12S};
237 Operand op;
238 int i;
240 parse_operand(s1, &ops[0]);
241 if ( tok == ',')
242 next();
243 else
244 expect("','");
246 if ( tok == '(') {
247 /* `X, (Y)` case*/
248 next();
249 parse_operand(s1, &ops[1]);
250 if ( tok == ')') next(); else expect("')'");
251 ops[2] = zimm;
252 } else {
253 parse_operand(s1, &ops[2]);
254 if ( tok == '('){
255 /* `X, imm(Y)` case*/
256 next();
257 parse_operand(s1, &ops[1]);
258 if ( tok == ')') next(); else expect("')'");
259 } else {
260 /* `X, Y` case*/
261 /* we parsed Y thinking it was imm, swap and default imm to zero */
262 op = ops[2];
263 ops[1] = ops[2];
264 ops[2] = op;
265 ops[2] = zimm;
270 /* This is special: First operand is optional */
271 static void asm_jal_opcode(TCCState *s1, int token){
272 static const Operand ra = {.type = OP_REG, .reg = 1};
273 Operand ops[2];
274 parse_operand(s1, &ops[0]);
275 if ( tok == ',')
276 next();
277 else {
278 /* no more operands, it's the pseudoinstruction:
279 * jal rs
280 * Expand to:
281 * jal ra, rs
283 asm_emit_j(token, 0x6f, &ra, &ops[0]);
284 return;
286 parse_operand(s1, &ops[1]);
287 asm_emit_j(token, 0x6f, &ops[0], &ops[1]);
290 /* This is special: It can be a pseudointruction or a instruction */
291 static void asm_jalr_opcode(TCCState *s1, int token){
292 static const Operand zimm = {.type = OP_IM12S};
293 static const Operand ra = {.type = OP_REG, .reg = 1};
294 Operand ops[3];
295 Operand op;
296 int i;
298 parse_operand(s1, &ops[0]);
299 if ( tok == ',')
300 next();
301 else {
302 /* no more operands, it's the pseudoinstruction:
303 * jalr rs
304 * Expand to:
305 * jalr ra, 0(rs)
307 asm_emit_i(token, 0x67 | (0 << 12), &ra, &ops[0], &zimm);
308 return;
311 if ( tok == '(') {
312 /* `X, (Y)` case*/
313 next();
314 parse_operand(s1, &ops[1]);
315 if ( tok == ')') next(); else expect("')'");
316 ops[2] = zimm;
317 } else {
318 parse_operand(s1, &ops[2]);
319 if ( tok == '('){
320 /* `X, imm(Y)` case*/
321 next();
322 parse_operand(s1, &ops[1]);
323 if ( tok == ')') next(); else expect("')'");
324 } else {
325 /* `X, Y` case*/
326 /* we parsed Y thinking it was imm, swap and default imm to zero */
327 op = ops[2];
328 ops[1] = ops[2];
329 ops[2] = op;
330 ops[2] = zimm;
333 /* jalr(RD, RS1, IMM); I-format */
334 asm_emit_i(token, 0x67 | (0 << 12), &ops[0], &ops[1], &ops[2]);
338 static void asm_unary_opcode(TCCState *s1, int token)
340 uint32_t opcode = (0x1C << 2) | 3 | (2 << 12);
341 Operand op;
342 static const Operand zero = {.type = OP_REG};
343 static const Operand zimm = {.type = OP_IM12S};
345 parse_operands(s1, &op, 1);
346 /* Note: Those all map to CSR--so they are pseudo-instructions. */
347 opcode |= ENCODE_RD(op.reg);
349 switch (token) {
350 /* pseudoinstructions */
351 case TOK_ASM_rdcycle:
352 asm_emit_opcode(opcode | (0xC00 << 20));
353 return;
354 case TOK_ASM_rdcycleh:
355 asm_emit_opcode(opcode | (0xC80 << 20));
356 return;
357 case TOK_ASM_rdtime:
358 asm_emit_opcode(opcode | (0xC01 << 20) | ENCODE_RD(op.reg));
359 return;
360 case TOK_ASM_rdtimeh:
361 asm_emit_opcode(opcode | (0xC81 << 20) | ENCODE_RD(op.reg));
362 return;
363 case TOK_ASM_rdinstret:
364 asm_emit_opcode(opcode | (0xC02 << 20) | ENCODE_RD(op.reg));
365 return;
366 case TOK_ASM_rdinstreth:
367 asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
368 return;
370 case TOK_ASM_jr:
371 /* jalr zero, 0(rs)*/
372 asm_emit_i(token, 0x67 | (0 << 12), &zero, &op, &zimm);
373 return;
374 case TOK_ASM_call:
375 /* auipc ra, 0 */
376 greloca(cur_text_section, op.e.sym, ind, R_RISCV_CALL, 0);
377 asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(1));
378 /* jalr zero, 0(ra) */
379 asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(1));
380 return;
381 case TOK_ASM_tail:
382 /* auipc x6, 0 */
383 greloca(cur_text_section, op.e.sym, ind, R_RISCV_CALL, 0);
384 asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(6));
385 /* jalr zero, 0(x6) */
386 asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(6));
387 return;
389 /* C extension */
390 case TOK_ASM_c_j:
391 asm_emit_cj(token, 1 | (5 << 13), &op);
392 return;
393 case TOK_ASM_c_jal: /* RV32C-only */
394 asm_emit_cj(token, 1 | (1 << 13), &op);
395 return;
396 case TOK_ASM_c_jalr:
397 asm_emit_cr(token, 2 | (9 << 12), &op, &zero);
398 return;
399 case TOK_ASM_c_jr:
400 asm_emit_cr(token, 2 | (8 << 12), &op, &zero);
401 return;
402 default:
403 expect("unary instruction");
407 static void asm_emit_u(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
409 if (rd->type != OP_REG) {
410 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
411 return;
413 if (rs2->type != OP_IM12S && rs2->type != OP_IM32) {
414 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token, NULL));
415 return;
416 } else if (rs2->e.v >= 0x100000) {
417 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0xfffff", get_tok_str(token, NULL));
418 return;
420 /* U-type instruction:
421 31...12 imm[31:12]
422 11...7 rd
423 6...0 opcode */
424 gen_le32(opcode | ENCODE_RD(rd->reg) | (rs2->e.v << 12));
427 static void asm_binary_opcode(TCCState* s1, int token)
429 static const Operand zero = {.type = OP_REG, .reg = 0};
430 Operand imm = {.type = OP_IM12S, .e = {.v = 0}};
431 Operand ops[2];
432 parse_operands(s1, &ops[0], 2);
434 switch (token) {
435 case TOK_ASM_lui:
436 asm_emit_u(token, (0xD << 2) | 3, &ops[0], &ops[1]);
437 return;
438 case TOK_ASM_auipc:
439 asm_emit_u(token, (0x05 << 2) | 3, &ops[0], &ops[1]);
440 return;
442 /* C extension */
443 case TOK_ASM_c_add:
444 asm_emit_cr(token, 2 | (9 << 12), ops, ops + 1);
445 return;
446 case TOK_ASM_c_mv:
447 asm_emit_cr(token, 2 | (8 << 12), ops, ops + 1);
448 return;
450 case TOK_ASM_c_addi16sp:
451 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
452 return;
453 case TOK_ASM_c_addi:
454 asm_emit_ci(token, 1, ops, ops + 1);
455 return;
456 case TOK_ASM_c_addiw:
457 asm_emit_ci(token, 1 | (1 << 13), ops, ops + 1);
458 return;
459 case TOK_ASM_c_fldsp:
460 asm_emit_ci(token, 2 | (1 << 13), ops, ops + 1);
461 return;
462 case TOK_ASM_c_flwsp: /* RV32FC-only */
463 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
464 return;
465 case TOK_ASM_c_ldsp:
466 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
467 return;
468 case TOK_ASM_c_li:
469 asm_emit_ci(token, 1 | (2 << 13), ops, ops + 1);
470 return;
471 case TOK_ASM_c_lui:
472 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
473 return;
474 case TOK_ASM_c_lwsp:
475 asm_emit_ci(token, 2 | (2 << 13), ops, ops + 1);
476 return;
477 case TOK_ASM_c_slli:
478 asm_emit_ci(token, 2, ops, ops + 1);
479 return;
481 case TOK_ASM_c_addi4spn:
482 asm_emit_ciw(token, 0, ops, ops + 1);
483 return;
485 #define CA (1 | (3 << 10) | (4 << 13))
486 case TOK_ASM_c_addw:
487 asm_emit_ca(token, CA | (1 << 5) | (1 << 12), ops, ops + 1);
488 return;
489 case TOK_ASM_c_and:
490 asm_emit_ca(token, CA | (3 << 5), ops, ops + 1);
491 return;
492 case TOK_ASM_c_or:
493 asm_emit_ca(token, CA | (2 << 5), ops, ops + 1);
494 return;
495 case TOK_ASM_c_sub:
496 asm_emit_ca(token, CA, ops, ops + 1);
497 return;
498 case TOK_ASM_c_subw:
499 asm_emit_ca(token, CA | (1 << 12), ops, ops + 1);
500 return;
501 case TOK_ASM_c_xor:
502 asm_emit_ca(token, CA | (1 << 5), ops, ops + 1);
503 return;
504 #undef CA
506 case TOK_ASM_c_andi:
507 asm_emit_cb(token, 1 | (2 << 10) | (4 << 13), ops, ops + 1);
508 return;
509 case TOK_ASM_c_beqz:
510 asm_emit_cb(token, 1 | (6 << 13), ops, ops + 1);
511 return;
512 case TOK_ASM_c_bnez:
513 asm_emit_cb(token, 1 | (7 << 13), ops, ops + 1);
514 return;
515 case TOK_ASM_c_srai:
516 asm_emit_cb(token, 1 | (1 << 10) | (4 << 13), ops, ops + 1);
517 return;
518 case TOK_ASM_c_srli:
519 asm_emit_cb(token, 1 | (4 << 13), ops, ops + 1);
520 return;
522 case TOK_ASM_c_sdsp:
523 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
524 return;
525 case TOK_ASM_c_swsp:
526 asm_emit_css(token, 2 | (6 << 13), ops, ops + 1);
527 return;
528 case TOK_ASM_c_fswsp: /* RV32FC-only */
529 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
530 return;
531 case TOK_ASM_c_fsdsp:
532 asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
533 return;
535 /* pseudoinstructions */
536 /* rd, sym */
537 case TOK_ASM_la:
538 /* auipc rd, 0 */
539 asm_emit_u(token, 3 | (5 << 2), ops, ops + 1);
540 /* lw rd, rd, 0 */
541 asm_emit_i(token, 3 | (2 << 12), ops, ops, ops + 1);
542 return;
543 case TOK_ASM_lla:
544 /* auipc rd, 0 */
545 asm_emit_u(token, 3 | (5 << 2), ops, ops + 1);
546 /* addi rd, rd, 0 */
547 asm_emit_i(token, 3 | (4 << 2), ops, ops, ops + 1);
548 return;
549 case TOK_ASM_li:
550 if(ops[1].type != OP_IM32 && ops[1].type != OP_IM12S){
551 tcc_error("'%s': Expected first source operand that is an immediate value between 0 and 0xFFFFFFFFFFFFFFFF", get_tok_str(token, NULL));
553 int32_t lo = ops[1].e.v;
554 uint32_t hi = (int64_t)ops[1].e.v >> 32;
555 if(lo < 0){
556 hi += 1;
558 imm.e.v = ((hi + 0x800) & 0xfffff000) >> 12;
559 /* lui rd, HI_20(HI_32(imm)) */
560 asm_emit_u(token, (0xD << 2) | 3, &ops[0], &imm);
561 /* addi rd, rd, LO_12(HI_32(imm)) */
562 imm.e.v = (int32_t)hi<<20>>20;
563 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm);
564 /* slli rd, rd, 12 */
565 imm.e.v = 12;
566 asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[0], &imm);
567 /* addi rd, rd, HI_12(LO_32(imm)) */
568 imm.e.v = (lo + (1<<19)) >> 20;
569 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm);
570 /* slli rd, rd, 12 */
571 imm.e.v = 12;
572 asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[0], &imm);
573 /* addi rd, rd, HI_12(LO_20(LO_32imm)) */
574 lo = lo << 12 >> 12;
575 imm.e.v = lo >> 8;
576 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm);
577 /* slli rd, rd, 8 */
578 imm.e.v = 8;
579 asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[0], &imm);
580 /* addi rd, rd, LO_8(LO_20(LO_32imm)) */
581 lo &= 0xff;
582 imm.e.v = lo << 20 >> 20;
583 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm);
584 return;
585 case TOK_ASM_mv:
586 /* addi rd, rs, 0 */
587 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[1], &imm);
588 return;
589 case TOK_ASM_not:
590 /* xori rd, rs, -1 */
591 imm.e.v = -1;
592 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &imm);
593 return;
594 case TOK_ASM_neg:
595 /* sub rd, x0, rs */
596 imm.e.v = 1;
597 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
598 return;
599 case TOK_ASM_negw:
600 /* sub rd, x0, rs */
601 imm.e.v = 1;
602 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
603 return;
604 case TOK_ASM_jump:
605 /* auipc x5, 0 */
606 asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(5));
607 greloca(cur_text_section, ops->e.sym, ind, R_RISCV_CALL, 0);
608 /* jalr zero, 0(x5) */
609 asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(5));
610 return;
611 case TOK_ASM_seqz:
612 /* sltiu rd, rs, 1 */
613 imm.e.v = 1;
614 asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &imm);
615 return;
616 case TOK_ASM_snez:
617 /* sltu rd, zero, rs */
618 imm.e.v = 1;
619 asm_emit_r(token, (0xC << 2) | 3 | (3 << 12), &ops[0], &zero, &ops[1]);
620 return;
621 case TOK_ASM_sltz:
622 /* slt rd, rs, zero */
623 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &ops[1], &zero);
624 return;
625 case TOK_ASM_sgtz:
626 /* slt rd, zero, rs */
627 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]);
628 return;
629 case TOK_ASM_bnez:
630 /* bne rs, zero, offset */
631 asm_emit_b(token, 0x63 | (1 << 12), &ops[0], &zero, &ops[1]);
632 return;
633 case TOK_ASM_beqz:
634 /* bne rs, zero, offset */
635 asm_emit_b(token, 0x63 | (0 << 12), &ops[0], &zero, &ops[1]);
636 return;
637 case TOK_ASM_blez:
638 /* bge rs, zero, offset */
639 asm_emit_b(token, 0x63 | (5 << 12), &ops[0], &zero, &ops[1]);
640 return;
641 case TOK_ASM_bgez:
642 /* bge zero, rs, offset */
643 asm_emit_b(token, 0x63 | (5 << 12), &zero, &ops[0], &ops[1]);
644 return;
645 case TOK_ASM_bltz:
646 /* blt rs, zero, offset */
647 asm_emit_b(token, 0x63 | (4 << 12), &ops[0], &zero, &ops[1]);
648 return;
649 case TOK_ASM_bgtz:
650 /* blt zero, rs, offset */
651 asm_emit_b(token, 0x63 | (4 << 12), &zero, &ops[0], &ops[1]);
652 return;
654 default:
655 expect("binary instruction");
659 /* caller: Add funct3, funct7 into opcode */
660 static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
662 if (rd->type != OP_REG) {
663 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
664 return;
666 if (rs1->type != OP_REG) {
667 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
668 return;
670 if (rs2->type != OP_REG) {
671 tcc_error("'%s': Expected second source operand that is a register or immediate", get_tok_str(token, NULL));
672 return;
674 /* R-type instruction:
675 31...25 funct7
676 24...20 rs2
677 19...15 rs1
678 14...12 funct3
679 11...7 rd
680 6...0 opcode */
681 gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
684 /* caller: Add funct3 into opcode */
685 static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
687 if (rd->type != OP_REG) {
688 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
689 return;
691 if (rs1->type != OP_REG) {
692 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
693 return;
695 if (rs2->type != OP_IM12S) {
696 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
697 return;
699 /* I-type instruction:
700 31...20 imm[11:0]
701 19...15 rs1
702 14...12 funct3
703 11...7 rd
704 6...0 opcode */
706 gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | (rs2->e.v << 20));
709 static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
711 uint32_t imm;
713 if (rd->type != OP_REG) {
714 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
715 return;
717 if (rs2->type != OP_IM12S && rs2->type != OP_IM32) {
718 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token, NULL));
719 return;
722 imm = rs2->e.v;
724 /* even offsets in a +- 1 MiB range */
725 if (imm > 0x1ffffe) {
726 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0x1fffff", get_tok_str(token, NULL));
727 return;
730 if (imm & 1) {
731 tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token, NULL));
732 return;
734 /* J-type instruction:
735 31 imm[20]
736 30...21 imm[10:1]
737 20 imm[11]
738 19...12 imm[19:12]
739 11...7 rd
740 6...0 opcode */
741 gen_le32(opcode | ENCODE_RD(rd->reg) | (((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3ff) << 21) | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xff) << 12));
744 static void asm_mem_access_opcode(TCCState *s1, int token)
747 Operand ops[3];
748 parse_mem_access_operands(s1, &ops[0]);
750 /* Pseudoinstruction: inst reg, label
751 * expand to:
752 * auipc reg, 0
753 * inst reg, 0(reg)
754 * And with the proper relocation to label
756 if (ops[1].type == OP_IM32 && ops[1].e.sym && ops[1].e.sym->type.t & VT_STATIC){
757 ops[1] = ops[0];
758 /* set the offset to zero */
759 ops[2].type = OP_IM12S;
760 ops[2].e.v = 0;
761 /* auipc reg, 0 */
762 asm_emit_u(token, (0x05 << 2) | 3, &ops[0], &ops[2]);
765 switch (token) {
766 // l{b|h|w|d}[u] rd, imm(rs1); I-format
767 case TOK_ASM_lb:
768 asm_emit_i(token, (0x0 << 2) | 3, &ops[0], &ops[1], &ops[2]);
769 return;
770 case TOK_ASM_lh:
771 asm_emit_i(token, (0x0 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
772 return;
773 case TOK_ASM_lw:
774 asm_emit_i(token, (0x0 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
775 return;
776 case TOK_ASM_ld:
777 asm_emit_i(token, (0x0 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
778 return;
779 case TOK_ASM_lbu:
780 asm_emit_i(token, (0x0 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
781 return;
782 case TOK_ASM_lhu:
783 asm_emit_i(token, (0x0 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
784 return;
785 case TOK_ASM_lwu:
786 asm_emit_i(token, (0x0 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
787 return;
789 // s{b|h|w|d} rs2, imm(rs1); S-format (with rsX swapped)
790 case TOK_ASM_sb:
791 asm_emit_s(token, (0x8 << 2) | 3 | (0 << 12), &ops[1], &ops[0], &ops[2]);
792 return;
793 case TOK_ASM_sh:
794 asm_emit_s(token, (0x8 << 2) | 3 | (1 << 12), &ops[1], &ops[0], &ops[2]);
795 return;
796 case TOK_ASM_sw:
797 asm_emit_s(token, (0x8 << 2) | 3 | (2 << 12), &ops[1], &ops[0], &ops[2]);
798 return;
799 case TOK_ASM_sd:
800 asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[1], &ops[0], &ops[2]);
801 return;
805 static void asm_ternary_opcode(TCCState *s1, int token)
807 Operand ops[3];
808 parse_operands(s1, &ops[0], 3);
810 switch (token) {
811 case TOK_ASM_sll:
812 asm_emit_r(token, (0xC << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
813 return;
814 case TOK_ASM_slli:
815 asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
816 return;
817 case TOK_ASM_srl:
818 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
819 return;
820 case TOK_ASM_srli:
821 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
822 return;
823 case TOK_ASM_sra:
824 asm_emit_r(token, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
825 return;
826 case TOK_ASM_srai:
827 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops[0], &ops[1], &ops[2]);
828 return;
829 case TOK_ASM_sllw:
830 asm_emit_r(token, (0xE << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
831 return;
832 case TOK_ASM_slliw:
833 asm_emit_i(token, (6 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
834 return;
835 case TOK_ASM_srlw:
836 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
837 return;
838 case TOK_ASM_srliw:
839 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
840 return;
841 case TOK_ASM_sraw:
842 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
843 return;
844 case TOK_ASM_sraiw:
845 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
846 return;
848 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
850 case TOK_ASM_add:
851 asm_emit_r(token, (0xC << 2) | 3, &ops[0], &ops[1], &ops[2]);
852 return;
853 case TOK_ASM_addi:
854 asm_emit_i(token, (4 << 2) | 3, &ops[0], &ops[1], &ops[2]);
855 return;
856 case TOK_ASM_sub:
857 asm_emit_r(token, (0xC << 2) | 3 | (32 << 25), &ops[0], &ops[1], &ops[2]);
858 return;
859 case TOK_ASM_addw:
860 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
861 return;
862 case TOK_ASM_addiw: // 64 bit
863 asm_emit_i(token, (0x6 << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
864 return;
865 case TOK_ASM_subw:
866 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
867 return;
869 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
871 case TOK_ASM_xor:
872 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
873 return;
874 case TOK_ASM_xori:
875 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
876 return;
877 case TOK_ASM_or:
878 asm_emit_r(token, (0xC << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
879 return;
880 case TOK_ASM_ori:
881 asm_emit_i(token, (0x4 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
882 return;
883 case TOK_ASM_and:
884 asm_emit_r(token, (0xC << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
885 return;
886 case TOK_ASM_andi:
887 asm_emit_i(token, (0x4 << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
888 return;
890 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
892 case TOK_ASM_slt:
893 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
894 return;
895 case TOK_ASM_slti:
896 asm_emit_i(token, (0x4 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
897 return;
898 case TOK_ASM_sltu:
899 asm_emit_r(token, (0xC << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
900 return;
901 case TOK_ASM_sltiu:
902 asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
903 return;
905 /* branch (RS1, RS2, IMM); B-format */
906 case TOK_ASM_beq:
907 asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2);
908 return;
909 case TOK_ASM_bne:
910 asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2);
911 return;
912 case TOK_ASM_blt:
913 asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2);
914 return;
915 case TOK_ASM_bge:
916 asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2);
917 return;
918 case TOK_ASM_bltu:
919 asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2);
920 return;
921 case TOK_ASM_bgeu:
922 asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2);
923 return;
924 /* related pseudoinstructions */
925 case TOK_ASM_bgt:
926 asm_emit_b(token, 0x63 | (4 << 12), ops + 1, ops, ops + 2);
927 return;
928 case TOK_ASM_ble:
929 asm_emit_b(token, 0x63 | (5 << 12), ops + 1, ops, ops + 2);
930 return;
931 case TOK_ASM_bgtu:
932 asm_emit_b(token, 0x63 | (6 << 12), ops + 1, ops, ops + 2);
933 return;
934 case TOK_ASM_bleu:
935 asm_emit_b(token, 0x63 | (7 << 12), ops + 1, ops, ops + 2);
936 return;
938 /* M extension */
939 case TOK_ASM_div:
940 asm_emit_r(token, 0x33 | (4 << 12) | (1 << 25), ops, ops + 1, ops + 2);
941 return;
942 case TOK_ASM_divu:
943 asm_emit_r(token, 0x33 | (5 << 12) | (1 << 25), ops, ops + 1, ops + 2);
944 return;
945 case TOK_ASM_divuw:
946 asm_emit_r(token, 0x3b | (5 << 12) | (1 << 25), ops, ops + 1, ops + 2);
947 return;
948 case TOK_ASM_divw:
949 asm_emit_r(token, 0x3b | (4 << 12) | (1 << 25), ops, ops + 1, ops + 2);
950 return;
951 case TOK_ASM_mul:
952 asm_emit_r(token, 0x33 | (1 << 25), ops, ops + 1, ops + 2);
953 return;
954 case TOK_ASM_mulh:
955 asm_emit_r(token, 0x33 | (1 << 12) | (1 << 25), ops, ops + 1, ops + 2);
956 return;
957 case TOK_ASM_mulhsu:
958 asm_emit_r(token, 0x33 | (2 << 12) | (1 << 25), ops, ops + 1, ops + 2);
959 return;
960 case TOK_ASM_mulhu:
961 asm_emit_r(token, 0x33 | (3 << 12) | (1 << 25), ops, ops + 1, ops + 2);
962 return;
963 case TOK_ASM_mulw:
964 asm_emit_r(token, 0x3b | (1 << 25), ops, ops + 1, ops + 2);
965 return;
966 case TOK_ASM_rem:
967 asm_emit_r(token, 0x33 | (6 << 12) | (1 << 25), ops, ops + 1, ops + 2);
968 return;
969 case TOK_ASM_remu:
970 asm_emit_r(token, 0x33 | (7 << 12) | (1 << 25), ops, ops + 1, ops + 2);
971 return;
972 case TOK_ASM_remuw:
973 asm_emit_r(token, 0x3b | (7 << 12) | (1 << 25), ops, ops + 1, ops + 2);
974 return;
975 case TOK_ASM_remw:
976 asm_emit_r(token, 0x3b | (6 << 12) | (1 << 25), ops, ops + 1, ops + 2);
977 return;
979 /* Zicsr extension; (rd, csr, rs/uimm) */
980 case TOK_ASM_csrrc:
981 asm_emit_i(token, 0x73 | (3 << 12), ops, ops + 2, ops + 1);
982 return;
983 case TOK_ASM_csrrci:
984 /* using rs1 field for uimmm */
985 ops[2].type = OP_REG;
986 asm_emit_i(token, 0x73 | (7 << 12), ops, ops + 2, ops + 1);
987 return;
988 case TOK_ASM_csrrs:
989 asm_emit_i(token, 0x73 | (2 << 12), ops, ops + 2, ops + 1);
990 return;
991 case TOK_ASM_csrrsi:
992 ops[2].type = OP_REG;
993 asm_emit_i(token, 0x73 | (6 << 12), ops, ops + 2, ops + 1);
994 return;
995 case TOK_ASM_csrrw:
996 asm_emit_i(token, 0x73 | (1 << 12), ops, ops + 2, ops + 1);
997 return;
998 case TOK_ASM_csrrwi:
999 ops[2].type = OP_REG;
1000 asm_emit_i(token, 0x73 | (5 << 12), ops, ops + 2, ops + 1);
1001 return;
1003 /* C extension */
1004 /* register-based loads and stores (RD, RS1, IMM); CL-format */
1005 case TOK_ASM_c_fld:
1006 asm_emit_cl(token, 1 << 13, ops, ops + 1, ops + 2);
1007 return;
1008 case TOK_ASM_c_flw: /* RV32FC-only */
1009 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
1010 return;
1011 case TOK_ASM_c_fsd:
1012 asm_emit_cs(token, 5 << 13, ops, ops + 1, ops + 2);
1013 return;
1014 case TOK_ASM_c_fsw: /* RV32FC-only */
1015 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
1016 return;
1017 case TOK_ASM_c_ld:
1018 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
1019 return;
1020 case TOK_ASM_c_lw:
1021 asm_emit_cl(token, 2 << 13, ops, ops + 1, ops + 2);
1022 return;
1023 case TOK_ASM_c_sd:
1024 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
1025 return;
1026 case TOK_ASM_c_sw:
1027 asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
1028 return;
1030 default:
1031 expect("ternary instruction");
1035 /* caller: Add funct3 to opcode */
1036 static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
1038 if (rs1->type != OP_REG) {
1039 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
1040 return;
1042 if (rs2->type != OP_REG) {
1043 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
1044 return;
1046 if (imm->type != OP_IM12S) {
1047 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
1048 return;
1051 uint16_t v = imm->e.v;
1052 /* S-type instruction:
1053 31...25 imm[11:5]
1054 24...20 rs2
1055 19...15 rs1
1056 14...12 funct3
1057 11...7 imm[4:0]
1058 6...0 opcode
1059 opcode always fixed pos. */
1060 gen_le32(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | ((v & 0x1F) << 7) | ((v >> 5) << 25));
1064 static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm)
1066 uint32_t offset;
1068 if (rs1->type != OP_REG) {
1069 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
1070 return;
1072 if (rs2->type != OP_REG) {
1073 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1074 return;
1076 if (imm->type != OP_IM12S) {
1077 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
1078 return;
1081 offset = imm->e.v;
1083 /* B-type instruction:
1084 31 imm[12]
1085 30...25 imm[10:5]
1086 24...20 rs2
1087 19...15 rs1
1088 14...12 funct3
1089 8...11 imm[4:1]
1090 7 imm[11]
1091 6...0 opcode */
1092 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));
1095 ST_FUNC void asm_opcode(TCCState *s1, int token)
1097 switch (token) {
1098 case TOK_ASM_ebreak:
1099 case TOK_ASM_ecall:
1100 case TOK_ASM_fence:
1101 case TOK_ASM_fence_i:
1102 case TOK_ASM_hrts:
1103 case TOK_ASM_mrth:
1104 case TOK_ASM_mrts:
1105 case TOK_ASM_wfi:
1106 asm_nullary_opcode(s1, token);
1107 return;
1109 case TOK_ASM_rdcycle:
1110 case TOK_ASM_rdcycleh:
1111 case TOK_ASM_rdtime:
1112 case TOK_ASM_rdtimeh:
1113 case TOK_ASM_rdinstret:
1114 case TOK_ASM_rdinstreth:
1115 asm_unary_opcode(s1, token);
1116 return;
1118 case TOK_ASM_lui:
1119 case TOK_ASM_auipc:
1120 asm_binary_opcode(s1, token);
1121 return;
1123 case TOK_ASM_lb:
1124 case TOK_ASM_lh:
1125 case TOK_ASM_lw:
1126 case TOK_ASM_ld:
1127 case TOK_ASM_lbu:
1128 case TOK_ASM_lhu:
1129 case TOK_ASM_lwu:
1130 case TOK_ASM_sb:
1131 case TOK_ASM_sh:
1132 case TOK_ASM_sw:
1133 case TOK_ASM_sd:
1134 asm_mem_access_opcode(s1, token);
1135 break;
1137 case TOK_ASM_jalr:
1138 asm_jalr_opcode(s1, token); /* it can be a pseudo instruction too*/
1139 break;
1140 case TOK_ASM_jal:
1141 asm_jal_opcode(s1, token); /* it can be a pseudo instruction too*/
1142 break;
1144 case TOK_ASM_add:
1145 case TOK_ASM_addi:
1146 case TOK_ASM_addiw:
1147 case TOK_ASM_addw:
1148 case TOK_ASM_and:
1149 case TOK_ASM_andi:
1150 case TOK_ASM_beq:
1151 case TOK_ASM_bge:
1152 case TOK_ASM_bgeu:
1153 case TOK_ASM_blt:
1154 case TOK_ASM_bltu:
1155 case TOK_ASM_bne:
1156 case TOK_ASM_or:
1157 case TOK_ASM_ori:
1158 case TOK_ASM_sll:
1159 case TOK_ASM_slli:
1160 case TOK_ASM_slliw:
1161 case TOK_ASM_sllw:
1162 case TOK_ASM_slt:
1163 case TOK_ASM_slti:
1164 case TOK_ASM_sltiu:
1165 case TOK_ASM_sltu:
1166 case TOK_ASM_sra:
1167 case TOK_ASM_srai:
1168 case TOK_ASM_sraiw:
1169 case TOK_ASM_sraw:
1170 case TOK_ASM_srl:
1171 case TOK_ASM_srli:
1172 case TOK_ASM_srliw:
1173 case TOK_ASM_srlw:
1174 case TOK_ASM_sub:
1175 case TOK_ASM_subw:
1176 case TOK_ASM_xor:
1177 case TOK_ASM_xori:
1178 /* M extension */
1179 case TOK_ASM_div:
1180 case TOK_ASM_divu:
1181 case TOK_ASM_divuw:
1182 case TOK_ASM_divw:
1183 case TOK_ASM_mul:
1184 case TOK_ASM_mulh:
1185 case TOK_ASM_mulhsu:
1186 case TOK_ASM_mulhu:
1187 case TOK_ASM_mulw:
1188 case TOK_ASM_rem:
1189 case TOK_ASM_remu:
1190 case TOK_ASM_remuw:
1191 case TOK_ASM_remw:
1192 /* Zicsr extension */
1193 case TOK_ASM_csrrc:
1194 case TOK_ASM_csrrci:
1195 case TOK_ASM_csrrs:
1196 case TOK_ASM_csrrsi:
1197 case TOK_ASM_csrrw:
1198 case TOK_ASM_csrrwi:
1199 asm_ternary_opcode(s1, token);
1200 return;
1202 /* C extension */
1203 case TOK_ASM_c_ebreak:
1204 case TOK_ASM_c_nop:
1205 asm_nullary_opcode(s1, token);
1206 return;
1208 case TOK_ASM_c_j:
1209 case TOK_ASM_c_jal:
1210 case TOK_ASM_c_jalr:
1211 case TOK_ASM_c_jr:
1212 asm_unary_opcode(s1, token);
1213 return;
1215 case TOK_ASM_c_add:
1216 case TOK_ASM_c_addi16sp:
1217 case TOK_ASM_c_addi4spn:
1218 case TOK_ASM_c_addi:
1219 case TOK_ASM_c_addiw:
1220 case TOK_ASM_c_addw:
1221 case TOK_ASM_c_and:
1222 case TOK_ASM_c_andi:
1223 case TOK_ASM_c_beqz:
1224 case TOK_ASM_c_bnez:
1225 case TOK_ASM_c_fldsp:
1226 case TOK_ASM_c_flwsp:
1227 case TOK_ASM_c_fsdsp:
1228 case TOK_ASM_c_fswsp:
1229 case TOK_ASM_c_ldsp:
1230 case TOK_ASM_c_li:
1231 case TOK_ASM_c_lui:
1232 case TOK_ASM_c_lwsp:
1233 case TOK_ASM_c_mv:
1234 case TOK_ASM_c_or:
1235 case TOK_ASM_c_sdsp:
1236 case TOK_ASM_c_slli:
1237 case TOK_ASM_c_srai:
1238 case TOK_ASM_c_srli:
1239 case TOK_ASM_c_sub:
1240 case TOK_ASM_c_subw:
1241 case TOK_ASM_c_swsp:
1242 case TOK_ASM_c_xor:
1243 asm_binary_opcode(s1, token);
1244 return;
1246 case TOK_ASM_c_fld:
1247 case TOK_ASM_c_flw:
1248 case TOK_ASM_c_fsd:
1249 case TOK_ASM_c_fsw:
1250 case TOK_ASM_c_ld:
1251 case TOK_ASM_c_lw:
1252 case TOK_ASM_c_sd:
1253 case TOK_ASM_c_sw:
1254 asm_ternary_opcode(s1, token);
1255 return;
1257 /* pseudoinstructions */
1258 case TOK_ASM_nop:
1259 case TOK_ASM_ret:
1260 asm_nullary_opcode(s1, token);
1261 return;
1263 case TOK_ASM_jr:
1264 case TOK_ASM_call:
1265 case TOK_ASM_tail:
1266 asm_unary_opcode(s1, token);
1267 return;
1269 case TOK_ASM_la:
1270 case TOK_ASM_lla:
1271 case TOK_ASM_li:
1272 case TOK_ASM_jump:
1273 case TOK_ASM_seqz:
1274 case TOK_ASM_snez:
1275 case TOK_ASM_sltz:
1276 case TOK_ASM_sgtz:
1277 case TOK_ASM_bnez:
1278 case TOK_ASM_beqz:
1279 case TOK_ASM_blez:
1280 case TOK_ASM_bgez:
1281 case TOK_ASM_bltz:
1282 case TOK_ASM_bgtz:
1283 case TOK_ASM_mv:
1284 case TOK_ASM_not:
1285 case TOK_ASM_neg:
1286 case TOK_ASM_negw:
1287 asm_binary_opcode(s1, token);
1288 return;
1290 case TOK_ASM_bgt:
1291 case TOK_ASM_bgtu:
1292 case TOK_ASM_ble:
1293 case TOK_ASM_bleu:
1294 asm_ternary_opcode(s1, token);
1295 return;
1297 default:
1298 expect("known instruction");
1302 static int asm_parse_csrvar(int t)
1304 switch (t) {
1305 case TOK_ASM_cycle:
1306 return 0xc00;
1307 case TOK_ASM_fcsr:
1308 return 3;
1309 case TOK_ASM_fflags:
1310 return 1;
1311 case TOK_ASM_frm:
1312 return 2;
1313 case TOK_ASM_instret:
1314 return 0xc02;
1315 case TOK_ASM_time:
1316 return 0xc01;
1317 case TOK_ASM_cycleh:
1318 return 0xc80;
1319 case TOK_ASM_instreth:
1320 return 0xc82;
1321 case TOK_ASM_timeh:
1322 return 0xc81;
1323 default:
1324 return -1;
1328 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
1330 tcc_error("RISCV64 asm not implemented.");
1333 /* generate prolog and epilog code for asm statement */
1334 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
1335 int nb_outputs, int is_output,
1336 uint8_t *clobber_regs,
1337 int out_reg)
1341 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
1342 int nb_operands, int nb_outputs,
1343 const uint8_t *clobber_regs,
1344 int *pout_reg)
1348 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
1350 int reg;
1351 TokenSym *ts;
1353 if (!strcmp(str, "memory") ||
1354 !strcmp(str, "cc") ||
1355 !strcmp(str, "flags"))
1356 return;
1357 ts = tok_alloc(str, strlen(str));
1358 reg = asm_parse_regvar(ts->tok);
1359 if (reg == -1) {
1360 tcc_error("invalid clobber register '%s'", str);
1362 clobber_regs[reg] = 1;
1365 ST_FUNC int asm_parse_regvar (int t)
1367 /* PC register not implemented */
1368 if (t >= TOK_ASM_pc || t < TOK_ASM_x0)
1369 return -1;
1371 if (t < TOK_ASM_f0)
1372 return t - TOK_ASM_x0;
1374 if (t < TOK_ASM_zero)
1375 return t - TOK_ASM_f0;
1377 /* ABI mnemonic */
1378 if (t < TOK_ASM_ft0)
1379 return t - TOK_ASM_zero;
1381 return t - TOK_ASM_ft0;
1384 /*************************************************************/
1385 /* C extension */
1387 /* caller: Add funct6, funct2 into opcode */
1388 static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
1390 uint8_t dst, src;
1392 if (rd->type != OP_REG) {
1393 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1394 return;
1397 if (rs2->type != OP_REG) {
1398 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1399 return;
1402 /* subtract index of x8 */
1403 dst = rd->reg - 8;
1404 src = rs2->reg - 8;
1406 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
1407 if (dst > 7) {
1408 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1409 return;
1412 if (src > 7) {
1413 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1414 return;
1417 /* CA-type instruction:
1418 15...10 funct6
1419 9...7 rd'/rs1'
1420 6..5 funct2
1421 4...2 rs2'
1422 1...0 opcode */
1424 gen_le16(opcode | C_ENCODE_RS2(src) | C_ENCODE_RS1(dst));
1427 static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm)
1429 uint32_t offset;
1430 uint8_t src;
1432 if (rs1->type != OP_REG) {
1433 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1434 return;
1437 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1438 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1439 return;
1442 offset = imm->e.v;
1444 if (offset & 1) {
1445 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
1446 return;
1449 src = rs1->reg - 8;
1451 if (src > 7) {
1452 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1453 return;
1456 /* CB-type instruction:
1457 15...13 funct3
1458 12...10 offset
1459 9..7 rs1'
1460 6...2 offset
1461 1...0 opcode */
1463 /* non-branch also using CB:
1464 15...13 funct3
1465 12 imm
1466 11..10 funct2
1467 9...7 rd'/rs1'
1468 6..2 imm
1469 1...0 opcode */
1471 switch (token) {
1472 case TOK_ASM_c_beqz:
1473 case TOK_ASM_c_bnez:
1474 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));
1475 return;
1476 default:
1477 gen_le16(opcode | C_ENCODE_RS1(src) | ((offset & 0x1f) << 2) | (NTH_BIT(offset, 5) << 12));
1478 return;
1482 static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
1484 uint32_t immediate;
1486 if (rd->type != OP_REG) {
1487 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1488 return;
1491 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1492 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1493 return;
1496 immediate = imm->e.v;
1498 /* CI-type instruction:
1499 15...13 funct3
1500 12 imm
1501 11...7 rd/rs1
1502 6...2 imm
1503 1...0 opcode */
1505 switch (token) {
1506 case TOK_ASM_c_addi:
1507 case TOK_ASM_c_addiw:
1508 case TOK_ASM_c_li:
1509 case TOK_ASM_c_slli:
1510 gen_le16(opcode | ((immediate & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1511 return;
1512 case TOK_ASM_c_addi16sp:
1513 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));
1514 return;
1515 case TOK_ASM_c_lui:
1516 gen_le16(opcode | (((immediate >> 12) & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 17) << 12));
1517 return;
1518 case TOK_ASM_c_fldsp:
1519 case TOK_ASM_c_ldsp:
1520 gen_le16(opcode | (((immediate >> 6) & 7) << 2) | (((immediate >> 3) & 2) << 5) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1521 return;
1522 case TOK_ASM_c_flwsp:
1523 case TOK_ASM_c_lwsp:
1524 gen_le16(opcode | (((immediate >> 6) & 3) << 2) | (((immediate >> 2) & 7) << 4) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1525 return;
1526 case TOK_ASM_c_nop:
1527 gen_le16(opcode);
1528 return;
1529 default:
1530 expect("known instruction");
1534 /* caller: Add funct3 into opcode */
1535 static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
1537 uint32_t nzuimm;
1538 uint8_t dst;
1540 if (rd->type != OP_REG) {
1541 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1542 return;
1545 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1546 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1547 return;
1550 dst = rd->reg - 8;
1552 if (dst > 7) {
1553 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1554 return;
1557 nzuimm = imm->e.v;
1559 if (nzuimm > 0x3fc) {
1560 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x3ff", get_tok_str(token, NULL));
1561 return;
1564 if (nzuimm & 3) {
1565 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token, NULL));
1566 return;
1569 /* CIW-type instruction:
1570 15...13 funct3
1571 12...5 imm
1572 4...2 rd'
1573 1...0 opcode */
1575 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));
1578 /* caller: Add funct3 into opcode */
1579 static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm)
1581 uint32_t offset;
1583 /* +-2 KiB range */
1584 if (imm->type != OP_IM12S) {
1585 tcc_error("'%s': Expected source operand that is a 12-bit immediate value", get_tok_str(token, NULL));
1586 return;
1589 offset = imm->e.v;
1591 if (offset & 1) {
1592 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
1593 return;
1596 /* CJ-type instruction:
1597 15...13 funct3
1598 12...2 offset[11|4|9:8|10|6|7|3:1|5]
1599 1...0 opcode */
1601 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));
1604 /* caller: Add funct3 into opcode */
1605 static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm)
1607 uint32_t offset;
1608 uint8_t dst, src;
1610 if (rd->type != OP_REG) {
1611 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1612 return;
1615 if (rs1->type != OP_REG) {
1616 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1617 return;
1620 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1621 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1622 return;
1625 dst = rd->reg - 8;
1626 src = rs1->reg - 8;
1628 if (dst > 7) {
1629 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1630 return;
1633 if (src > 7) {
1634 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1635 return;
1638 offset = imm->e.v;
1640 if (offset > 0xff) {
1641 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1642 return;
1645 if (offset & 3) {
1646 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1647 return;
1650 /* CL-type instruction:
1651 15...13 funct3
1652 12...10 imm
1653 9...7 rs1'
1654 6...5 imm
1655 4...2 rd'
1656 1...0 opcode */
1658 switch (token) {
1659 /* imm variant 1 */
1660 case TOK_ASM_c_flw:
1661 case TOK_ASM_c_lw:
1662 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));
1663 return;
1664 /* imm variant 2 */
1665 case TOK_ASM_c_fld:
1666 case TOK_ASM_c_ld:
1667 gen_le16(opcode | C_ENCODE_RS2(dst) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
1668 return;
1669 default:
1670 expect("known instruction");
1674 /* caller: Add funct4 into opcode */
1675 static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
1677 if (rd->type != OP_REG) {
1678 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1679 return;
1682 if (rs2->type != OP_REG) {
1683 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1684 return;
1687 /* CR-type instruction:
1688 15...12 funct4
1689 11..7 rd/rs1
1690 6...2 rs2
1691 1...0 opcode */
1693 gen_le16(opcode | C_ENCODE_RS1(rd->reg) | C_ENCODE_RS2(rs2->reg));
1696 /* caller: Add funct3 into opcode */
1697 static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm)
1699 uint32_t offset;
1700 uint8_t base, src;
1702 if (rs2->type != OP_REG) {
1703 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1704 return;
1707 if (rs1->type != OP_REG) {
1708 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1709 return;
1712 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1713 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1714 return;
1717 base = rs1->reg - 8;
1718 src = rs2->reg - 8;
1720 if (base > 7) {
1721 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1722 return;
1725 if (src > 7) {
1726 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1727 return;
1730 offset = imm->e.v;
1732 if (offset > 0xff) {
1733 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1734 return;
1737 if (offset & 3) {
1738 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1739 return;
1742 /* CS-type instruction:
1743 15...13 funct3
1744 12...10 imm
1745 9...7 rs1'
1746 6...5 imm
1747 4...2 rs2'
1748 1...0 opcode */
1749 switch (token) {
1750 /* imm variant 1 */
1751 case TOK_ASM_c_fsw:
1752 case TOK_ASM_c_sw:
1753 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));
1754 return;
1755 /* imm variant 2 */
1756 case TOK_ASM_c_fsd:
1757 case TOK_ASM_c_sd:
1758 gen_le16(opcode | C_ENCODE_RS2(base) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
1759 return;
1760 default:
1761 expect("known instruction");
1765 /* caller: Add funct3 into opcode */
1766 static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm)
1768 uint32_t offset;
1770 if (rs2->type != OP_REG) {
1771 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1772 return;
1775 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1776 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1777 return;
1780 offset = imm->e.v;
1782 if (offset > 0xff) {
1783 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1784 return;
1787 if (offset & 3) {
1788 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1789 return;
1792 /* CSS-type instruction:
1793 15...13 funct3
1794 12...7 imm
1795 6...2 rs2
1796 1...0 opcode */
1798 switch (token) {
1799 /* imm variant 1 */
1800 case TOK_ASM_c_fswsp:
1801 case TOK_ASM_c_swsp:
1802 gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 3) << 7) | (((offset >> 2) & 0xf) << 9));
1803 return;
1804 /* imm variant 2 */
1805 case TOK_ASM_c_fsdsp:
1806 case TOK_ASM_c_sdsp:
1807 gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 7) << 7) | (((offset >> 3) & 7) << 10));
1808 return;
1809 default:
1810 expect("known instruction");
1814 /*************************************************************/
1815 #endif /* ndef TARGET_DEFS_ONLY */