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 static void parse_operands(TCCState
*s1
, Operand
*ops
, int count
);
66 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
);
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 ? */
85 if (ind1
> cur_text_section
->data_allocated
)
86 section_realloc(cur_text_section
, ind1
);
87 cur_text_section
->data
[ind
] = c
;
91 ST_FUNC
void gen_le16 (int i
)
97 ST_FUNC
void gen_le32 (int i
)
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
)
116 static void asm_emit_opcode(uint32_t 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
};
128 case TOK_ASM_fence
: // I
129 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
131 case TOK_ASM_fence_i
: // I
132 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
137 case TOK_ASM_ecall
: // I (pseudo)
138 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
140 case TOK_ASM_ebreak
: // I (pseudo)
141 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
147 asm_emit_i(token
, (4 << 2) | 3, &nil
, &nil
, &zimm
);
151 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
155 case TOK_ASM_c_ebreak
:
156 asm_emit_cr(token
, 2 | (9 << 12), &nil
, &nil
);
159 asm_emit_ci(token
, 1, &nil
, &zimm
);
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
)
176 if ((reg
= asm_parse_regvar(tok
)) != -1) {
177 next(); // skip register name
179 op
->reg
= (uint8_t) reg
;
181 } else if (tok
== '$') {
183 next(); // skip '#' or '$'
184 } else if ((e
.v
= asm_parse_csrvar(tok
)) != -1) {
191 /* compare against unsigned 12-bit maximum */
193 if ((int) op
->e
.v
>= -0x1000 && (int) op
->e
.v
< 0x1000)
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);
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);
213 static void parse_operands(TCCState
*s1
, Operand
* ops
, int count
){
215 for (i
= 0; i
< count
; i
++) {
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);
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
);
237 /* pseudoinstructions */
238 case TOK_ASM_rdcycle
:
239 asm_emit_opcode(opcode
| (0xC00 << 20));
241 case TOK_ASM_rdcycleh
:
242 asm_emit_opcode(opcode
| (0xC80 << 20));
245 asm_emit_opcode(opcode
| (0xC01 << 20) | ENCODE_RD(op
.reg
));
247 case TOK_ASM_rdtimeh
:
248 asm_emit_opcode(opcode
| (0xC81 << 20) | ENCODE_RD(op
.reg
));
250 case TOK_ASM_rdinstret
:
251 asm_emit_opcode(opcode
| (0xC02 << 20) | ENCODE_RD(op
.reg
));
253 case TOK_ASM_rdinstreth
:
254 asm_emit_opcode(opcode
| (0xC82 << 20) | ENCODE_RD(op
.reg
));
258 asm_emit_cj(token
, 1 | (5 << 13), &op
);
260 case TOK_ASM_c_jal
: /* RV32C-only */
261 asm_emit_cj(token
, 1 | (1 << 13), &op
);
264 asm_emit_cr(token
, 2 | (9 << 12), &op
, &nil
);
267 asm_emit_cr(token
, 2 | (8 << 12), &op
, &nil
);
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
));
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
));
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
));
287 /* U-type instruction:
291 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | (rs2
->e
.v
<< 12));
294 static void asm_binary_opcode(TCCState
* s1
, int token
)
297 parse_operands(s1
, &ops
[0], 2);
301 asm_emit_u(token
, (0xD << 2) | 3, &ops
[0], &ops
[1]);
304 asm_emit_u(token
, (0x05 << 2) | 3, &ops
[0], &ops
[1]);
307 asm_emit_j(token
, 0x6f, ops
, ops
+ 1);
312 asm_emit_cr(token
, 2 | (9 << 12), ops
, ops
+ 1);
315 asm_emit_cr(token
, 2 | (8 << 12), ops
, ops
+ 1);
318 case TOK_ASM_c_addi16sp
:
319 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
322 asm_emit_ci(token
, 1, ops
, ops
+ 1);
324 case TOK_ASM_c_addiw
:
325 asm_emit_ci(token
, 1 | (1 << 13), ops
, ops
+ 1);
327 case TOK_ASM_c_fldsp
:
328 asm_emit_ci(token
, 2 | (1 << 13), ops
, ops
+ 1);
330 case TOK_ASM_c_flwsp
: /* RV32FC-only */
331 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
334 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
337 asm_emit_ci(token
, 1 | (2 << 13), ops
, ops
+ 1);
340 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
343 asm_emit_ci(token
, 2 | (2 << 13), ops
, ops
+ 1);
346 asm_emit_ci(token
, 2, ops
, ops
+ 1);
349 case TOK_ASM_c_addi4spn
:
350 asm_emit_ciw(token
, 0, ops
, ops
+ 1);
353 #define CA (1 | (3 << 10) | (4 << 13))
355 asm_emit_ca(token
, CA
| (1 << 5) | (1 << 12), ops
, ops
+ 1);
358 asm_emit_ca(token
, CA
| (3 << 5), ops
, ops
+ 1);
361 asm_emit_ca(token
, CA
| (2 << 5), ops
, ops
+ 1);
364 asm_emit_ca(token
, CA
, ops
, ops
+ 1);
367 asm_emit_ca(token
, CA
| (1 << 12), ops
, ops
+ 1);
370 asm_emit_ca(token
, CA
| (1 << 5), ops
, ops
+ 1);
375 asm_emit_cb(token
, 1 | (2 << 10) | (4 << 13), ops
, ops
+ 1);
378 asm_emit_cb(token
, 1 | (6 << 13), ops
, ops
+ 1);
381 asm_emit_cb(token
, 1 | (7 << 13), ops
, ops
+ 1);
384 asm_emit_cb(token
, 1 | (1 << 10) | (4 << 13), ops
, ops
+ 1);
387 asm_emit_cb(token
, 1 | (4 << 13), ops
, ops
+ 1);
391 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
394 asm_emit_css(token
, 2 | (6 << 13), ops
, ops
+ 1);
396 case TOK_ASM_c_fswsp
: /* RV32FC-only */
397 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
399 case TOK_ASM_c_fsdsp
:
400 asm_emit_css(token
, 2 | (5 << 13), ops
, ops
+ 1);
403 /* pseudoinstructions */
407 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
409 asm_emit_i(token
, 3 | (2 << 12), ops
, ops
, ops
+ 1);
413 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
415 asm_emit_i(token
, 3 | (4 << 2), ops
, ops
, ops
+ 1);
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
));
430 if (rs1
->type
!= OP_REG
) {
431 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
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
));
438 /* R-type instruction:
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
));
455 if (rs1
->type
!= OP_REG
) {
456 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
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
));
463 /* I-type instruction:
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
)
477 if (rd
->type
!= OP_REG
) {
478 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
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
));
495 tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token
, NULL
));
498 /* J-type instruction:
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
)
511 parse_operands(s1
, &ops
[0], 3);
515 asm_emit_r(token
, (0xC << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
518 asm_emit_i(token
, (4 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
521 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
524 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
527 asm_emit_r(token
, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
530 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops
[0], &ops
[1], &ops
[2]);
533 asm_emit_r(token
, (0xE << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
536 asm_emit_i(token
, (6 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
539 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
542 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
545 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
548 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
551 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
554 asm_emit_r(token
, (0xC << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
557 asm_emit_i(token
, (4 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
560 asm_emit_r(token
, (0xC << 2) | 3 | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
563 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
565 case TOK_ASM_addiw
: // 64 bit
566 asm_emit_i(token
, (0x6 << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
569 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
572 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
575 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
578 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
581 asm_emit_r(token
, (0xC << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
584 asm_emit_i(token
, (0x4 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
587 asm_emit_r(token
, (0xC << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
590 asm_emit_i(token
, (0x4 << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
593 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
596 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
599 asm_emit_i(token
, (0x4 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
602 asm_emit_r(token
, (0xC << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
605 asm_emit_i(token
, (0x4 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
608 /* indirect jump (RD, RS1, IMM); I-format */
610 asm_emit_i(token
, 0x67 | (0 << 12), ops
, ops
+ 1, ops
+ 2);
613 /* branch (RS1, RS2, IMM); B-format */
615 asm_emit_b(token
, 0x63 | (0 << 12), ops
, ops
+ 1, ops
+ 2);
618 asm_emit_b(token
, 0x63 | (1 << 12), ops
, ops
+ 1, ops
+ 2);
621 asm_emit_b(token
, 0x63 | (4 << 12), ops
, ops
+ 1, ops
+ 2);
624 asm_emit_b(token
, 0x63 | (5 << 12), ops
, ops
+ 1, ops
+ 2);
627 asm_emit_b(token
, 0x63 | (6 << 12), ops
, ops
+ 1, ops
+ 2);
630 asm_emit_b(token
, 0x63 | (7 << 12), ops
, ops
+ 1, ops
+ 2);
633 // Loads (RD,RS1,I); I-format
636 asm_emit_i(token
, (0x0 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
639 asm_emit_i(token
, (0x0 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
642 asm_emit_i(token
, (0x0 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
645 asm_emit_i(token
, (0x0 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
648 asm_emit_i(token
, (0x0 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
652 asm_emit_i(token
, (0x0 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
655 asm_emit_i(token
, (0x0 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
658 // Stores (RS1,RS2,I); S-format
661 asm_emit_s(token
, (0x8 << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
664 asm_emit_s(token
, (0x8 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
667 asm_emit_s(token
, (0x8 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
670 asm_emit_s(token
, (0x8 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
675 asm_emit_r(token
, 0x33 | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
678 asm_emit_r(token
, 0x33 | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
681 asm_emit_r(token
, 0x3b | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
684 asm_emit_r(token
, 0x3b | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
687 asm_emit_r(token
, 0x33 | (1 << 25), ops
, ops
+ 1, ops
+ 2);
690 asm_emit_r(token
, 0x33 | (1 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
693 asm_emit_r(token
, 0x33 | (2 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
696 asm_emit_r(token
, 0x33 | (3 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
699 asm_emit_r(token
, 0x3b | (1 << 25), ops
, ops
+ 1, ops
+ 2);
702 asm_emit_r(token
, 0x33 | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
705 asm_emit_r(token
, 0x33 | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
708 asm_emit_r(token
, 0x3b | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
711 asm_emit_r(token
, 0x3b | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
714 /* Zicsr extension; (rd, csr, rs/uimm) */
716 asm_emit_i(token
, 0x73 | (3 << 12), ops
, ops
+ 2, ops
+ 1);
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);
724 asm_emit_i(token
, 0x73 | (2 << 12), ops
, ops
+ 2, ops
+ 1);
727 ops
[2].type
= OP_REG
;
728 asm_emit_i(token
, 0x73 | (6 << 12), ops
, ops
+ 2, ops
+ 1);
731 asm_emit_i(token
, 0x73 | (1 << 12), ops
, ops
+ 2, ops
+ 1);
734 ops
[2].type
= OP_REG
;
735 asm_emit_i(token
, 0x73 | (5 << 12), ops
, ops
+ 2, ops
+ 1);
739 /* register-based loads and stores (RD, RS1, IMM); CL-format */
741 asm_emit_cl(token
, 1 << 13, ops
, ops
+ 1, ops
+ 2);
743 case TOK_ASM_c_flw
: /* RV32FC-only */
744 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
747 asm_emit_cs(token
, 5 << 13, ops
, ops
+ 1, ops
+ 2);
749 case TOK_ASM_c_fsw
: /* RV32FC-only */
750 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
753 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
756 asm_emit_cl(token
, 2 << 13, ops
, ops
+ 1, ops
+ 2);
759 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
762 asm_emit_cs(token
, 6 << 13, ops
, ops
+ 1, ops
+ 2);
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
));
777 if (rs2
->type
!= OP_REG
) {
778 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token
, NULL
));
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
));
786 uint16_t v
= imm
->e
.v
;
787 /* S-type instruction:
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
)
803 if (rs1
->type
!= OP_REG
) {
804 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
807 if (rs2
->type
!= OP_REG
) {
808 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
818 /* B-type instruction:
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
)
836 case TOK_ASM_fence_i
:
841 asm_nullary_opcode(s1
, token
);
844 case TOK_ASM_rdcycle
:
845 case TOK_ASM_rdcycleh
:
847 case TOK_ASM_rdtimeh
:
848 case TOK_ASM_rdinstret
:
849 case TOK_ASM_rdinstreth
:
850 asm_unary_opcode(s1
, token
);
856 asm_binary_opcode(s1
, token
);
919 /* Zicsr extension */
926 asm_ternary_opcode(s1
, token
);
930 case TOK_ASM_c_ebreak
:
932 asm_nullary_opcode(s1
, token
);
939 asm_unary_opcode(s1
, token
);
943 case TOK_ASM_c_addi16sp
:
944 case TOK_ASM_c_addi4spn
:
946 case TOK_ASM_c_addiw
:
952 case TOK_ASM_c_fldsp
:
953 case TOK_ASM_c_flwsp
:
954 case TOK_ASM_c_fsdsp
:
955 case TOK_ASM_c_fswsp
:
970 asm_binary_opcode(s1
, token
);
981 asm_ternary_opcode(s1
, token
);
984 /* pseudoinstructions */
986 asm_nullary_opcode(s1
, token
);
991 asm_binary_opcode(s1
, token
);
995 expect("known instruction");
999 static int asm_parse_csrvar(int t
)
1006 case TOK_ASM_fflags
:
1010 case TOK_ASM_instret
:
1014 case TOK_ASM_cycleh
:
1016 case TOK_ASM_instreth
:
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
,
1038 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1039 int nb_operands
, int nb_outputs
,
1040 const uint8_t *clobber_regs
,
1045 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1050 if (!strcmp(str
, "memory") ||
1051 !strcmp(str
, "cc") ||
1052 !strcmp(str
, "flags"))
1054 ts
= tok_alloc(str
, strlen(str
));
1055 reg
= asm_parse_regvar(ts
->tok
);
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
)
1069 return t
- TOK_ASM_x0
;
1071 if (t
< TOK_ASM_zero
)
1072 return t
- TOK_ASM_f0
;
1075 if (t
< TOK_ASM_ft0
)
1076 return t
- TOK_ASM_zero
;
1078 return t
- TOK_ASM_ft0
;
1081 /*************************************************************/
1084 /* caller: Add funct6, funct2 into opcode */
1085 static void asm_emit_ca(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
)
1089 if (rd
->type
!= OP_REG
) {
1090 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1094 if (rs2
->type
!= OP_REG
) {
1095 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1099 /* subtract index of x8 */
1103 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
1105 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1110 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1114 /* CA-type instruction:
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
)
1129 if (rs1
->type
!= OP_REG
) {
1130 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
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
));
1142 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
1149 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1153 /* CB-type instruction:
1160 /* non-branch also using CB:
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));
1174 gen_le16(opcode
| C_ENCODE_RS1(src
) | ((offset
& 0x1f) << 2) | (NTH_BIT(offset
, 5) << 12));
1179 static void asm_emit_ci(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
)
1183 if (rd
->type
!= OP_REG
) {
1184 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
1193 immediate
= imm
->e
.v
;
1195 /* CI-type instruction:
1203 case TOK_ASM_c_addi
:
1204 case TOK_ASM_c_addiw
:
1206 case TOK_ASM_c_slli
:
1207 gen_le16(opcode
| ((immediate
& 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
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));
1213 gen_le16(opcode
| (((immediate
>> 12) & 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 17) << 12));
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));
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));
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
)
1237 if (rd
->type
!= OP_REG
) {
1238 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
1250 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
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
));
1262 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token
, NULL
));
1266 /* CIW-type instruction:
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
)
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
));
1289 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
1293 /* CJ-type instruction:
1295 12...2 offset[11|4|9:8|10|6|7|3:1|5]
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
)
1307 if (rd
->type
!= OP_REG
) {
1308 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1312 if (rs1
->type
!= OP_REG
) {
1313 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
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
));
1326 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1331 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
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
));
1343 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1347 /* CL-type instruction:
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));
1364 gen_le16(opcode
| C_ENCODE_RS2(dst
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
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
));
1379 if (rs2
->type
!= OP_REG
) {
1380 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1384 /* CR-type instruction:
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
)
1399 if (rs2
->type
!= OP_REG
) {
1400 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1404 if (rs1
->type
!= OP_REG
) {
1405 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
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
));
1414 base
= rs1
->reg
- 8;
1418 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1423 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
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
));
1435 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1439 /* CS-type instruction:
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));
1455 gen_le16(opcode
| C_ENCODE_RS2(base
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
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
)
1467 if (rs2
->type
!= OP_REG
) {
1468 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
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
));
1485 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1489 /* CSS-type instruction:
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));
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));
1507 expect("known instruction");
1511 /*************************************************************/
1512 #endif /* ndef TARGET_DEFS_ONLY */