1 /*************************************************************/
3 * RISCV64 assembler for TCC
7 #ifdef TARGET_DEFS_ONLY
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 /*************************************************************/
18 /*************************************************************/
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
{
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 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
);
67 static void asm_emit_ca(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
);
68 static void asm_emit_cb(int token
, uint16_t opcode
, const Operand
*rs1
, const Operand
*imm
);
69 static void asm_emit_ci(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
);
70 static void asm_emit_ciw(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
);
71 static void asm_emit_cj(int token
, uint16_t opcode
, const Operand
*imm
);
72 static void asm_emit_cl(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs1
, const Operand
*imm
);
73 static void asm_emit_cr(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
);
74 static void asm_emit_cs(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*rs1
, const Operand
*imm
);
75 static void asm_emit_css(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*imm
);
77 /* XXX: make it faster ? */
84 if (ind1
> cur_text_section
->data_allocated
)
85 section_realloc(cur_text_section
, ind1
);
86 cur_text_section
->data
[ind
] = c
;
90 ST_FUNC
void gen_le16 (int i
)
96 ST_FUNC
void gen_le32 (int i
)
102 if (ind1
> cur_text_section
->data_allocated
)
103 section_realloc(cur_text_section
, ind1
);
104 cur_text_section
->data
[ind
++] = i
& 0xFF;
105 cur_text_section
->data
[ind
++] = (i
>> 8) & 0xFF;
106 cur_text_section
->data
[ind
++] = (i
>> 16) & 0xFF;
107 cur_text_section
->data
[ind
++] = (i
>> 24) & 0xFF;
110 ST_FUNC
void gen_expr32(ExprValue
*pe
)
115 static void asm_emit_opcode(uint32_t opcode
) {
119 static void asm_nullary_opcode(TCCState
*s1
, int token
)
121 static const Operand nil
= {.type
= OP_REG
};
122 static const Operand zimm
= {.type
= OP_IM12S
};
127 case TOK_ASM_fence
: // I
128 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
130 case TOK_ASM_fence_i
: // I
131 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
136 case TOK_ASM_ecall
: // I (pseudo)
137 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
139 case TOK_ASM_ebreak
: // I (pseudo)
140 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
146 asm_emit_i(token
, (4 << 2) | 3, &nil
, &nil
, &zimm
);
150 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
154 case TOK_ASM_c_ebreak
:
155 asm_emit_cr(token
, 2 | (9 << 12), &nil
, &nil
);
158 asm_emit_ci(token
, 1, &nil
, &zimm
);
162 expect("nullary instruction");
166 /* Parse a text containing operand and store the result in OP */
167 static void parse_operand(TCCState
*s1
, Operand
*op
)
175 if ((reg
= asm_parse_regvar(tok
)) != -1) {
176 next(); // skip register name
178 op
->reg
= (uint8_t) reg
;
180 } else if (tok
== '$') {
182 next(); // skip '#' or '$'
183 } else if ((e
.v
= asm_parse_csrvar(tok
)) != -1) {
190 /* compare against unsigned 12-bit maximum */
192 if ((int) op
->e
.v
>= -0x1000 && (int) op
->e
.v
< 0x1000)
194 } else if (op
->e
.sym
->type
.t
& (VT_EXTERN
| VT_STATIC
)) {
195 label
.type
.t
= VT_VOID
| VT_STATIC
;
197 /* use the medium PIC model: GOT, auipc, lw */
198 if (op
->e
.sym
->type
.t
& VT_STATIC
)
199 greloca(cur_text_section
, op
->e
.sym
, ind
, R_RISCV_PCREL_HI20
, 0);
201 greloca(cur_text_section
, op
->e
.sym
, ind
, R_RISCV_GOT_HI20
, 0);
202 put_extern_sym(&label
, cur_text_section
, ind
, 0);
203 greloca(cur_text_section
, &label
, ind
+4, R_RISCV_PCREL_LO12_I
, 0);
212 static void asm_unary_opcode(TCCState
*s1
, int token
)
214 uint32_t opcode
= (0x1C << 2) | 3 | (2 << 12);
216 static const Operand nil
= {.type
= OP_REG
};
218 parse_operand(s1
, &op
);
219 /* Note: Those all map to CSR--so they are pseudo-instructions. */
220 opcode
|= ENCODE_RD(op
.reg
);
223 /* pseudoinstructions */
224 case TOK_ASM_rdcycle
:
225 asm_emit_opcode(opcode
| (0xC00 << 20));
227 case TOK_ASM_rdcycleh
:
228 asm_emit_opcode(opcode
| (0xC80 << 20));
231 asm_emit_opcode(opcode
| (0xC01 << 20) | ENCODE_RD(op
.reg
));
233 case TOK_ASM_rdtimeh
:
234 asm_emit_opcode(opcode
| (0xC81 << 20) | ENCODE_RD(op
.reg
));
236 case TOK_ASM_rdinstret
:
237 asm_emit_opcode(opcode
| (0xC02 << 20) | ENCODE_RD(op
.reg
));
239 case TOK_ASM_rdinstreth
:
240 asm_emit_opcode(opcode
| (0xC82 << 20) | ENCODE_RD(op
.reg
));
244 asm_emit_cj(token
, 1 | (5 << 13), &op
);
246 case TOK_ASM_c_jal
: /* RV32C-only */
247 asm_emit_cj(token
, 1 | (1 << 13), &op
);
250 asm_emit_cr(token
, 2 | (9 << 12), &op
, &nil
);
253 asm_emit_cr(token
, 2 | (8 << 12), &op
, &nil
);
256 expect("unary instruction");
260 static void asm_emit_u(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs2
)
262 if (rd
->type
!= OP_REG
) {
263 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
266 if (rs2
->type
!= OP_IM12S
&& rs2
->type
!= OP_IM32
) {
267 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token
, NULL
));
269 } else if (rs2
->e
.v
>= 0x100000) {
270 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0xfffff", get_tok_str(token
, NULL
));
273 /* U-type instruction:
277 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | (rs2
->e
.v
<< 12));
280 static void asm_binary_opcode(TCCState
* s1
, int token
)
283 parse_operand(s1
, &ops
[0]);
288 parse_operand(s1
, &ops
[1]);
292 asm_emit_u(token
, (0xD << 2) | 3, &ops
[0], &ops
[1]);
295 asm_emit_u(token
, (0x05 << 2) | 3, &ops
[0], &ops
[1]);
298 asm_emit_j(token
, 0x6f, ops
, ops
+ 1);
303 asm_emit_cr(token
, 2 | (9 << 12), ops
, ops
+ 1);
306 asm_emit_cr(token
, 2 | (8 << 12), ops
, ops
+ 1);
309 case TOK_ASM_c_addi16sp
:
310 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
313 asm_emit_ci(token
, 1, ops
, ops
+ 1);
315 case TOK_ASM_c_addiw
:
316 asm_emit_ci(token
, 1 | (1 << 13), ops
, ops
+ 1);
318 case TOK_ASM_c_fldsp
:
319 asm_emit_ci(token
, 2 | (1 << 13), ops
, ops
+ 1);
321 case TOK_ASM_c_flwsp
: /* RV32FC-only */
322 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
325 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
328 asm_emit_ci(token
, 1 | (2 << 13), ops
, ops
+ 1);
331 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
334 asm_emit_ci(token
, 2 | (2 << 13), ops
, ops
+ 1);
337 asm_emit_ci(token
, 2, ops
, ops
+ 1);
340 case TOK_ASM_c_addi4spn
:
341 asm_emit_ciw(token
, 0, ops
, ops
+ 1);
344 #define CA (1 | (3 << 10) | (4 << 13))
346 asm_emit_ca(token
, CA
| (1 << 5) | (1 << 12), ops
, ops
+ 1);
349 asm_emit_ca(token
, CA
| (3 << 5), ops
, ops
+ 1);
352 asm_emit_ca(token
, CA
| (2 << 5), ops
, ops
+ 1);
355 asm_emit_ca(token
, CA
, ops
, ops
+ 1);
358 asm_emit_ca(token
, CA
| (1 << 12), ops
, ops
+ 1);
361 asm_emit_ca(token
, CA
| (1 << 5), ops
, ops
+ 1);
366 asm_emit_cb(token
, 1 | (2 << 10) | (4 << 13), ops
, ops
+ 1);
369 asm_emit_cb(token
, 1 | (6 << 13), ops
, ops
+ 1);
372 asm_emit_cb(token
, 1 | (7 << 13), ops
, ops
+ 1);
375 asm_emit_cb(token
, 1 | (1 << 10) | (4 << 13), ops
, ops
+ 1);
378 asm_emit_cb(token
, 1 | (4 << 13), ops
, ops
+ 1);
382 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
385 asm_emit_css(token
, 2 | (6 << 13), ops
, ops
+ 1);
387 case TOK_ASM_c_fswsp
: /* RV32FC-only */
388 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
390 case TOK_ASM_c_fsdsp
:
391 asm_emit_css(token
, 2 | (5 << 13), ops
, ops
+ 1);
394 /* pseudoinstructions */
398 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
400 asm_emit_i(token
, 3 | (2 << 12), ops
, ops
, ops
+ 1);
404 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
406 asm_emit_i(token
, 3 | (4 << 2), ops
, ops
, ops
+ 1);
410 expect("binary instruction");
414 /* caller: Add funct3, funct7 into opcode */
415 static void asm_emit_r(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs1
, const Operand
* rs2
)
417 if (rd
->type
!= OP_REG
) {
418 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
421 if (rs1
->type
!= OP_REG
) {
422 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
425 if (rs2
->type
!= OP_REG
) {
426 tcc_error("'%s': Expected second source operand that is a register or immediate", get_tok_str(token
, NULL
));
429 /* R-type instruction:
436 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | ENCODE_RS1(rs1
->reg
) | ENCODE_RS2(rs2
->reg
));
439 /* caller: Add funct3 into opcode */
440 static void asm_emit_i(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs1
, const Operand
* rs2
)
442 if (rd
->type
!= OP_REG
) {
443 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
446 if (rs1
->type
!= OP_REG
) {
447 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
450 if (rs2
->type
!= OP_IM12S
) {
451 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token
, NULL
));
454 /* I-type instruction:
461 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | ENCODE_RS1(rs1
->reg
) | (rs2
->e
.v
<< 20));
464 static void asm_emit_j(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs2
)
468 if (rd
->type
!= OP_REG
) {
469 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
472 if (rs2
->type
!= OP_IM12S
&& rs2
->type
!= OP_IM32
) {
473 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token
, NULL
));
479 /* even offsets in a +- 1 MiB range */
480 if (imm
> 0x1ffffe) {
481 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0x1fffff", get_tok_str(token
, NULL
));
486 tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token
, NULL
));
489 /* J-type instruction:
496 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | (((imm
>> 20) & 1) << 31) | (((imm
>> 1) & 0x3ff) << 21) | (((imm
>> 11) & 1) << 20) | (((imm
>> 12) & 0xff) << 12));
499 static void asm_ternary_opcode(TCCState
*s1
, int token
)
502 parse_operand(s1
, &ops
[0]);
507 parse_operand(s1
, &ops
[1]);
512 parse_operand(s1
, &ops
[2]);
516 asm_emit_r(token
, (0xC << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
519 asm_emit_i(token
, (4 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
522 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
525 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
528 asm_emit_r(token
, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
531 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops
[0], &ops
[1], &ops
[2]);
534 asm_emit_r(token
, (0xE << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
537 asm_emit_i(token
, (6 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
540 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
543 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
546 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
549 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
552 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
555 asm_emit_r(token
, (0xC << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
558 asm_emit_i(token
, (4 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
561 asm_emit_r(token
, (0xC << 2) | 3 | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
564 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
566 case TOK_ASM_addiw
: // 64 bit
567 asm_emit_i(token
, (0x6 << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
570 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
573 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
576 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
579 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
582 asm_emit_r(token
, (0xC << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
585 asm_emit_i(token
, (0x4 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
588 asm_emit_r(token
, (0xC << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
591 asm_emit_i(token
, (0x4 << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
594 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
597 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
600 asm_emit_i(token
, (0x4 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
603 asm_emit_r(token
, (0xC << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
606 asm_emit_i(token
, (0x4 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
609 /* indirect jump (RD, RS1, IMM); I-format */
611 asm_emit_i(token
, 0x67 | (0 << 12), ops
, ops
+ 1, ops
+ 2);
614 /* branch (RS1, RS2, IMM); B-format */
616 asm_emit_b(token
, 0x63 | (0 << 12), ops
, ops
+ 1, ops
+ 2);
619 asm_emit_b(token
, 0x63 | (1 << 12), ops
, ops
+ 1, ops
+ 2);
622 asm_emit_b(token
, 0x63 | (4 << 12), ops
, ops
+ 1, ops
+ 2);
625 asm_emit_b(token
, 0x63 | (5 << 12), ops
, ops
+ 1, ops
+ 2);
628 asm_emit_b(token
, 0x63 | (6 << 12), ops
, ops
+ 1, ops
+ 2);
631 asm_emit_b(token
, 0x63 | (7 << 12), ops
, ops
+ 1, ops
+ 2);
634 // Loads (RD,RS1,I); I-format
637 asm_emit_i(token
, (0x0 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
640 asm_emit_i(token
, (0x0 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
643 asm_emit_i(token
, (0x0 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
646 asm_emit_i(token
, (0x0 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
649 asm_emit_i(token
, (0x0 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
653 asm_emit_i(token
, (0x0 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
656 asm_emit_i(token
, (0x0 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
659 // Stores (RS1,RS2,I); S-format
662 asm_emit_s(token
, (0x8 << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
665 asm_emit_s(token
, (0x8 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
668 asm_emit_s(token
, (0x8 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
671 asm_emit_s(token
, (0x8 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
676 asm_emit_r(token
, 0x33 | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
679 asm_emit_r(token
, 0x33 | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
682 asm_emit_r(token
, 0x3b | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
685 asm_emit_r(token
, 0x3b | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
688 asm_emit_r(token
, 0x33 | (1 << 25), ops
, ops
+ 1, ops
+ 2);
691 asm_emit_r(token
, 0x33 | (1 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
694 asm_emit_r(token
, 0x33 | (2 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
697 asm_emit_r(token
, 0x33 | (3 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
700 asm_emit_r(token
, 0x3b | (1 << 25), ops
, ops
+ 1, ops
+ 2);
703 asm_emit_r(token
, 0x33 | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
706 asm_emit_r(token
, 0x33 | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
709 asm_emit_r(token
, 0x3b | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
712 asm_emit_r(token
, 0x3b | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
715 /* Zicsr extension; (rd, csr, rs/uimm) */
717 asm_emit_i(token
, 0x73 | (3 << 12), ops
, ops
+ 2, ops
+ 1);
720 /* using rs1 field for uimmm */
721 ops
[2].type
= OP_REG
;
722 asm_emit_i(token
, 0x73 | (7 << 12), ops
, ops
+ 2, ops
+ 1);
725 asm_emit_i(token
, 0x73 | (2 << 12), ops
, ops
+ 2, ops
+ 1);
728 ops
[2].type
= OP_REG
;
729 asm_emit_i(token
, 0x73 | (6 << 12), ops
, ops
+ 2, ops
+ 1);
732 asm_emit_i(token
, 0x73 | (1 << 12), ops
, ops
+ 2, ops
+ 1);
735 ops
[2].type
= OP_REG
;
736 asm_emit_i(token
, 0x73 | (5 << 12), ops
, ops
+ 2, ops
+ 1);
740 /* register-based loads and stores (RD, RS1, IMM); CL-format */
742 asm_emit_cl(token
, 1 << 13, ops
, ops
+ 1, ops
+ 2);
744 case TOK_ASM_c_flw
: /* RV32FC-only */
745 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
748 asm_emit_cs(token
, 5 << 13, ops
, ops
+ 1, ops
+ 2);
750 case TOK_ASM_c_fsw
: /* RV32FC-only */
751 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
754 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
757 asm_emit_cl(token
, 2 << 13, ops
, ops
+ 1, ops
+ 2);
760 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
763 asm_emit_cs(token
, 6 << 13, ops
, ops
+ 1, ops
+ 2);
767 expect("ternary instruction");
771 /* caller: Add funct3 to opcode */
772 static void asm_emit_s(int token
, uint32_t opcode
, const Operand
* rs1
, const Operand
* rs2
, const Operand
* imm
)
774 if (rs1
->type
!= OP_REG
) {
775 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
778 if (rs2
->type
!= OP_REG
) {
779 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token
, NULL
));
782 if (imm
->type
!= OP_IM12S
) {
783 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token
, NULL
));
787 uint16_t v
= imm
->e
.v
;
788 /* S-type instruction:
795 opcode always fixed pos. */
796 gen_le32(opcode
| ENCODE_RS1(rs1
->reg
) | ENCODE_RS2(rs2
->reg
) | ((v
& 0x1F) << 7) | ((v
>> 5) << 25));
800 static void asm_emit_b(int token
, uint32_t opcode
, const Operand
*rs1
, const Operand
*rs2
, const Operand
*imm
)
804 if (rs1
->type
!= OP_REG
) {
805 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
808 if (rs2
->type
!= OP_REG
) {
809 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
812 if (imm
->type
!= OP_IM12S
) {
813 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token
, NULL
));
819 /* B-type instruction:
828 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));
831 ST_FUNC
void asm_opcode(TCCState
*s1
, int token
)
837 case TOK_ASM_fence_i
:
842 asm_nullary_opcode(s1
, token
);
845 case TOK_ASM_rdcycle
:
846 case TOK_ASM_rdcycleh
:
848 case TOK_ASM_rdtimeh
:
849 case TOK_ASM_rdinstret
:
850 case TOK_ASM_rdinstreth
:
851 asm_unary_opcode(s1
, token
);
857 asm_binary_opcode(s1
, token
);
920 /* Zicsr extension */
927 asm_ternary_opcode(s1
, token
);
931 case TOK_ASM_c_ebreak
:
933 asm_nullary_opcode(s1
, token
);
940 asm_unary_opcode(s1
, token
);
944 case TOK_ASM_c_addi16sp
:
945 case TOK_ASM_c_addi4spn
:
947 case TOK_ASM_c_addiw
:
953 case TOK_ASM_c_fldsp
:
954 case TOK_ASM_c_flwsp
:
955 case TOK_ASM_c_fsdsp
:
956 case TOK_ASM_c_fswsp
:
971 asm_binary_opcode(s1
, token
);
982 asm_ternary_opcode(s1
, token
);
985 /* pseudoinstructions */
987 asm_nullary_opcode(s1
, token
);
992 asm_binary_opcode(s1
, token
);
996 expect("known instruction");
1000 static int asm_parse_csrvar(int t
)
1007 case TOK_ASM_fflags
:
1011 case TOK_ASM_instret
:
1015 case TOK_ASM_cycleh
:
1017 case TOK_ASM_instreth
:
1026 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
)
1028 tcc_error("RISCV64 asm not implemented.");
1031 /* generate prolog and epilog code for asm statement */
1032 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
,
1033 int nb_outputs
, int is_output
,
1034 uint8_t *clobber_regs
,
1039 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1040 int nb_operands
, int nb_outputs
,
1041 const uint8_t *clobber_regs
,
1046 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1051 if (!strcmp(str
, "memory") ||
1052 !strcmp(str
, "cc") ||
1053 !strcmp(str
, "flags"))
1055 ts
= tok_alloc(str
, strlen(str
));
1056 reg
= asm_parse_regvar(ts
->tok
);
1058 tcc_error("invalid clobber register '%s'", str
);
1060 clobber_regs
[reg
] = 1;
1063 ST_FUNC
int asm_parse_regvar (int t
)
1065 /* PC register not implemented */
1066 if (t
>= TOK_ASM_pc
|| t
< TOK_ASM_x0
)
1070 return t
- TOK_ASM_x0
;
1072 if (t
< TOK_ASM_zero
)
1073 return t
- TOK_ASM_f0
;
1076 if (t
< TOK_ASM_ft0
)
1077 return t
- TOK_ASM_zero
;
1079 return t
- TOK_ASM_ft0
;
1082 /*************************************************************/
1085 /* caller: Add funct6, funct2 into opcode */
1086 static void asm_emit_ca(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
)
1090 if (rd
->type
!= OP_REG
) {
1091 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1095 if (rs2
->type
!= OP_REG
) {
1096 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1100 /* subtract index of x8 */
1104 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
1106 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1111 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1115 /* CA-type instruction:
1122 gen_le16(opcode
| C_ENCODE_RS2(src
) | C_ENCODE_RS1(dst
));
1125 static void asm_emit_cb(int token
, uint16_t opcode
, const Operand
*rs1
, const Operand
*imm
)
1130 if (rs1
->type
!= OP_REG
) {
1131 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1135 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1136 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1143 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
1150 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1154 /* CB-type instruction:
1161 /* non-branch also using CB:
1170 case TOK_ASM_c_beqz
:
1171 case TOK_ASM_c_bnez
:
1172 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));
1175 gen_le16(opcode
| C_ENCODE_RS1(src
) | ((offset
& 0x1f) << 2) | (NTH_BIT(offset
, 5) << 12));
1180 static void asm_emit_ci(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
)
1184 if (rd
->type
!= OP_REG
) {
1185 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1189 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1190 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1194 immediate
= imm
->e
.v
;
1196 /* CI-type instruction:
1204 case TOK_ASM_c_addi
:
1205 case TOK_ASM_c_addiw
:
1207 case TOK_ASM_c_slli
:
1208 gen_le16(opcode
| ((immediate
& 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
1210 case TOK_ASM_c_addi16sp
:
1211 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));
1214 gen_le16(opcode
| (((immediate
>> 12) & 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 17) << 12));
1216 case TOK_ASM_c_fldsp
:
1217 case TOK_ASM_c_ldsp
:
1218 gen_le16(opcode
| (((immediate
>> 6) & 7) << 2) | (((immediate
>> 3) & 2) << 5) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
1220 case TOK_ASM_c_flwsp
:
1221 case TOK_ASM_c_lwsp
:
1222 gen_le16(opcode
| (((immediate
>> 6) & 3) << 2) | (((immediate
>> 2) & 7) << 4) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
1228 expect("known instruction");
1232 /* caller: Add funct3 into opcode */
1233 static void asm_emit_ciw(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
)
1238 if (rd
->type
!= OP_REG
) {
1239 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1243 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1244 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1251 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1257 if (nzuimm
> 0x3fc) {
1258 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x3ff", get_tok_str(token
, NULL
));
1263 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token
, NULL
));
1267 /* CIW-type instruction:
1273 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));
1276 /* caller: Add funct3 into opcode */
1277 static void asm_emit_cj(int token
, uint16_t opcode
, const Operand
*imm
)
1282 if (imm
->type
!= OP_IM12S
) {
1283 tcc_error("'%s': Expected source operand that is a 12-bit immediate value", get_tok_str(token
, NULL
));
1290 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
1294 /* CJ-type instruction:
1296 12...2 offset[11|4|9:8|10|6|7|3:1|5]
1299 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));
1302 /* caller: Add funct3 into opcode */
1303 static void asm_emit_cl(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs1
, const Operand
*imm
)
1308 if (rd
->type
!= OP_REG
) {
1309 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1313 if (rs1
->type
!= OP_REG
) {
1314 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1318 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1319 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1327 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1332 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1338 if (offset
> 0xff) {
1339 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token
, NULL
));
1344 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1348 /* CL-type instruction:
1360 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));
1365 gen_le16(opcode
| C_ENCODE_RS2(dst
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
1368 expect("known instruction");
1372 /* caller: Add funct4 into opcode */
1373 static void asm_emit_cr(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
)
1375 if (rd
->type
!= OP_REG
) {
1376 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1380 if (rs2
->type
!= OP_REG
) {
1381 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1385 /* CR-type instruction:
1391 gen_le16(opcode
| C_ENCODE_RS1(rd
->reg
) | C_ENCODE_RS2(rs2
->reg
));
1394 /* caller: Add funct3 into opcode */
1395 static void asm_emit_cs(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*rs1
, const Operand
*imm
)
1400 if (rs2
->type
!= OP_REG
) {
1401 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1405 if (rs1
->type
!= OP_REG
) {
1406 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1410 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1411 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1415 base
= rs1
->reg
- 8;
1419 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1424 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1430 if (offset
> 0xff) {
1431 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token
, NULL
));
1436 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1440 /* CS-type instruction:
1451 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));
1456 gen_le16(opcode
| C_ENCODE_RS2(base
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
1459 expect("known instruction");
1463 /* caller: Add funct3 into opcode */
1464 static void asm_emit_css(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*imm
)
1468 if (rs2
->type
!= OP_REG
) {
1469 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1473 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1474 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1480 if (offset
> 0xff) {
1481 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token
, NULL
));
1486 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1490 /* CSS-type instruction:
1498 case TOK_ASM_c_fswsp
:
1499 case TOK_ASM_c_swsp
:
1500 gen_le16(opcode
| ENCODE_RS2(rs2
->reg
) | (((offset
>> 6) & 3) << 7) | (((offset
>> 2) & 0xf) << 9));
1503 case TOK_ASM_c_fsdsp
:
1504 case TOK_ASM_c_sdsp
:
1505 gen_le16(opcode
| ENCODE_RS2(rs2
->reg
) | (((offset
>> 6) & 7) << 7) | (((offset
>> 3) & 7) << 10));
1508 expect("known instruction");
1512 /*************************************************************/
1513 #endif /* ndef TARGET_DEFS_ONLY */