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 static void parse_mem_access_operands(TCCState
*s1
, Operand
* ops
);
67 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
);
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 ? */
86 if (ind1
> cur_text_section
->data_allocated
)
87 section_realloc(cur_text_section
, ind1
);
88 cur_text_section
->data
[ind
] = c
;
92 ST_FUNC
void gen_le16 (int i
)
98 ST_FUNC
void gen_le32 (int i
)
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
)
117 static void asm_emit_opcode(uint32_t 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
};
129 case TOK_ASM_fence
: // I
130 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
132 case TOK_ASM_fence_i
: // I
133 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
138 case TOK_ASM_ecall
: // I (pseudo)
139 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
141 case TOK_ASM_ebreak
: // I (pseudo)
142 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
148 asm_emit_i(token
, (4 << 2) | 3, &nil
, &nil
, &zimm
);
152 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
155 /* Pseudoinstructions */
157 /* jalr zero, x1, 0 */
158 asm_emit_opcode( 0x67 | (0 << 12) | ENCODE_RS1(1) );
162 case TOK_ASM_c_ebreak
:
163 asm_emit_cr(token
, 2 | (9 << 12), &nil
, &nil
);
166 asm_emit_ci(token
, 1, &nil
, &zimm
);
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
)
183 if ((reg
= asm_parse_regvar(tok
)) != -1) {
184 next(); // skip register name
186 op
->reg
= (uint8_t) reg
;
188 } else if (tok
== '$') {
190 next(); // skip '#' or '$'
191 } else if ((e
.v
= asm_parse_csrvar(tok
)) != -1) {
198 /* compare against unsigned 12-bit maximum */
200 if ((int) op
->e
.v
>= -0x1000 && (int) op
->e
.v
< 0x1000)
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);
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);
220 static void parse_operands(TCCState
*s1
, Operand
* ops
, int count
){
222 for (i
= 0; i
< count
; i
++) {
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
};
240 parse_operand(s1
, &ops
[0]);
249 parse_operand(s1
, &ops
[1]);
250 if ( tok
== ')') next(); else expect("')'");
253 parse_operand(s1
, &ops
[2]);
255 /* `X, imm(Y)` case*/
257 parse_operand(s1
, &ops
[1]);
258 if ( tok
== ')') next(); else expect("')'");
261 /* we parsed Y thinking it was imm, swap and default imm to zero */
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};
274 parse_operand(s1
, &ops
[0]);
278 /* no more operands, it's the pseudoinstruction:
283 asm_emit_j(token
, 0x6f, &ra
, &ops
[0]);
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};
298 parse_operand(s1
, &ops
[0]);
302 /* no more operands, it's the pseudoinstruction:
307 asm_emit_i(token
, 0x67 | (0 << 12), &ra
, &ops
[0], &zimm
);
314 parse_operand(s1
, &ops
[1]);
315 if ( tok
== ')') next(); else expect("')'");
318 parse_operand(s1
, &ops
[2]);
320 /* `X, imm(Y)` case*/
322 parse_operand(s1
, &ops
[1]);
323 if ( tok
== ')') next(); else expect("')'");
326 /* we parsed Y thinking it was imm, swap and default imm to zero */
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);
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
);
350 /* pseudoinstructions */
351 case TOK_ASM_rdcycle
:
352 asm_emit_opcode(opcode
| (0xC00 << 20));
354 case TOK_ASM_rdcycleh
:
355 asm_emit_opcode(opcode
| (0xC80 << 20));
358 asm_emit_opcode(opcode
| (0xC01 << 20) | ENCODE_RD(op
.reg
));
360 case TOK_ASM_rdtimeh
:
361 asm_emit_opcode(opcode
| (0xC81 << 20) | ENCODE_RD(op
.reg
));
363 case TOK_ASM_rdinstret
:
364 asm_emit_opcode(opcode
| (0xC02 << 20) | ENCODE_RD(op
.reg
));
366 case TOK_ASM_rdinstreth
:
367 asm_emit_opcode(opcode
| (0xC82 << 20) | ENCODE_RD(op
.reg
));
371 /* jalr zero, 0(rs)*/
372 asm_emit_i(token
, 0x67 | (0 << 12), &zero
, &op
, &zimm
);
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));
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));
391 asm_emit_cj(token
, 1 | (5 << 13), &op
);
393 case TOK_ASM_c_jal
: /* RV32C-only */
394 asm_emit_cj(token
, 1 | (1 << 13), &op
);
397 asm_emit_cr(token
, 2 | (9 << 12), &op
, &zero
);
400 asm_emit_cr(token
, 2 | (8 << 12), &op
, &zero
);
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
));
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
));
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
));
420 /* U-type instruction:
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}};
432 parse_operands(s1
, &ops
[0], 2);
436 asm_emit_u(token
, (0xD << 2) | 3, &ops
[0], &ops
[1]);
439 asm_emit_u(token
, (0x05 << 2) | 3, &ops
[0], &ops
[1]);
444 asm_emit_cr(token
, 2 | (9 << 12), ops
, ops
+ 1);
447 asm_emit_cr(token
, 2 | (8 << 12), ops
, ops
+ 1);
450 case TOK_ASM_c_addi16sp
:
451 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
454 asm_emit_ci(token
, 1, ops
, ops
+ 1);
456 case TOK_ASM_c_addiw
:
457 asm_emit_ci(token
, 1 | (1 << 13), ops
, ops
+ 1);
459 case TOK_ASM_c_fldsp
:
460 asm_emit_ci(token
, 2 | (1 << 13), ops
, ops
+ 1);
462 case TOK_ASM_c_flwsp
: /* RV32FC-only */
463 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
466 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
469 asm_emit_ci(token
, 1 | (2 << 13), ops
, ops
+ 1);
472 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
475 asm_emit_ci(token
, 2 | (2 << 13), ops
, ops
+ 1);
478 asm_emit_ci(token
, 2, ops
, ops
+ 1);
481 case TOK_ASM_c_addi4spn
:
482 asm_emit_ciw(token
, 0, ops
, ops
+ 1);
485 #define CA (1 | (3 << 10) | (4 << 13))
487 asm_emit_ca(token
, CA
| (1 << 5) | (1 << 12), ops
, ops
+ 1);
490 asm_emit_ca(token
, CA
| (3 << 5), ops
, ops
+ 1);
493 asm_emit_ca(token
, CA
| (2 << 5), ops
, ops
+ 1);
496 asm_emit_ca(token
, CA
, ops
, ops
+ 1);
499 asm_emit_ca(token
, CA
| (1 << 12), ops
, ops
+ 1);
502 asm_emit_ca(token
, CA
| (1 << 5), ops
, ops
+ 1);
507 asm_emit_cb(token
, 1 | (2 << 10) | (4 << 13), ops
, ops
+ 1);
510 asm_emit_cb(token
, 1 | (6 << 13), ops
, ops
+ 1);
513 asm_emit_cb(token
, 1 | (7 << 13), ops
, ops
+ 1);
516 asm_emit_cb(token
, 1 | (1 << 10) | (4 << 13), ops
, ops
+ 1);
519 asm_emit_cb(token
, 1 | (4 << 13), ops
, ops
+ 1);
523 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
526 asm_emit_css(token
, 2 | (6 << 13), ops
, ops
+ 1);
528 case TOK_ASM_c_fswsp
: /* RV32FC-only */
529 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
531 case TOK_ASM_c_fsdsp
:
532 asm_emit_css(token
, 2 | (5 << 13), ops
, ops
+ 1);
535 /* pseudoinstructions */
539 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
541 asm_emit_i(token
, 3 | (2 << 12), ops
, ops
, ops
+ 1);
545 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
547 asm_emit_i(token
, 3 | (4 << 2), ops
, ops
, ops
+ 1);
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;
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 */
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 */
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)) */
576 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[0], &imm
);
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)) */
582 imm
.e
.v
= lo
<< 20 >> 20;
583 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[0], &imm
);
587 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[1], &imm
);
590 /* xori rd, rs, -1 */
592 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &imm
);
597 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &zero
, &imm
);
602 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &zero
, &imm
);
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));
612 /* sltiu rd, rs, 1 */
614 asm_emit_i(token
, (0x4 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &imm
);
617 /* sltu rd, zero, rs */
619 asm_emit_r(token
, (0xC << 2) | 3 | (3 << 12), &ops
[0], &zero
, &ops
[1]);
622 /* slt rd, rs, zero */
623 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &zero
);
626 /* slt rd, zero, rs */
627 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &zero
, &ops
[1]);
630 /* bne rs, zero, offset */
631 asm_emit_b(token
, 0x63 | (1 << 12), &ops
[0], &zero
, &ops
[1]);
634 /* bne rs, zero, offset */
635 asm_emit_b(token
, 0x63 | (0 << 12), &ops
[0], &zero
, &ops
[1]);
638 /* bge rs, zero, offset */
639 asm_emit_b(token
, 0x63 | (5 << 12), &ops
[0], &zero
, &ops
[1]);
642 /* bge zero, rs, offset */
643 asm_emit_b(token
, 0x63 | (5 << 12), &zero
, &ops
[0], &ops
[1]);
646 /* blt rs, zero, offset */
647 asm_emit_b(token
, 0x63 | (4 << 12), &ops
[0], &zero
, &ops
[1]);
650 /* blt zero, rs, offset */
651 asm_emit_b(token
, 0x63 | (4 << 12), &zero
, &ops
[0], &ops
[1]);
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
));
666 if (rs1
->type
!= OP_REG
) {
667 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
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
));
674 /* R-type instruction:
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
));
691 if (rs1
->type
!= OP_REG
) {
692 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
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
));
699 /* I-type instruction:
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
)
713 if (rd
->type
!= OP_REG
) {
714 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
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
));
731 tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token
, NULL
));
734 /* J-type instruction:
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
)
748 parse_mem_access_operands(s1
, &ops
[0]);
750 /* Pseudoinstruction: inst reg, label
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
){
758 /* set the offset to zero */
759 ops
[2].type
= OP_IM12S
;
762 asm_emit_u(token
, (0x05 << 2) | 3, &ops
[0], &ops
[2]);
766 // l{b|h|w|d}[u] rd, imm(rs1); I-format
768 asm_emit_i(token
, (0x0 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
771 asm_emit_i(token
, (0x0 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
774 asm_emit_i(token
, (0x0 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
777 asm_emit_i(token
, (0x0 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
780 asm_emit_i(token
, (0x0 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
783 asm_emit_i(token
, (0x0 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
786 asm_emit_i(token
, (0x0 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
789 // s{b|h|w|d} rs2, imm(rs1); S-format (with rsX swapped)
791 asm_emit_s(token
, (0x8 << 2) | 3 | (0 << 12), &ops
[1], &ops
[0], &ops
[2]);
794 asm_emit_s(token
, (0x8 << 2) | 3 | (1 << 12), &ops
[1], &ops
[0], &ops
[2]);
797 asm_emit_s(token
, (0x8 << 2) | 3 | (2 << 12), &ops
[1], &ops
[0], &ops
[2]);
800 asm_emit_s(token
, (0x8 << 2) | 3 | (3 << 12), &ops
[1], &ops
[0], &ops
[2]);
805 static void asm_ternary_opcode(TCCState
*s1
, int token
)
808 parse_operands(s1
, &ops
[0], 3);
812 asm_emit_r(token
, (0xC << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
815 asm_emit_i(token
, (4 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
818 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
821 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
824 asm_emit_r(token
, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
827 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops
[0], &ops
[1], &ops
[2]);
830 asm_emit_r(token
, (0xE << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
833 asm_emit_i(token
, (6 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
836 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
839 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
842 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
845 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
848 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
851 asm_emit_r(token
, (0xC << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
854 asm_emit_i(token
, (4 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
857 asm_emit_r(token
, (0xC << 2) | 3 | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
860 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
862 case TOK_ASM_addiw
: // 64 bit
863 asm_emit_i(token
, (0x6 << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
866 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
869 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
872 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
875 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
878 asm_emit_r(token
, (0xC << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
881 asm_emit_i(token
, (0x4 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
884 asm_emit_r(token
, (0xC << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
887 asm_emit_i(token
, (0x4 << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
890 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
893 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
896 asm_emit_i(token
, (0x4 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
899 asm_emit_r(token
, (0xC << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
902 asm_emit_i(token
, (0x4 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
905 /* branch (RS1, RS2, IMM); B-format */
907 asm_emit_b(token
, 0x63 | (0 << 12), ops
, ops
+ 1, ops
+ 2);
910 asm_emit_b(token
, 0x63 | (1 << 12), ops
, ops
+ 1, ops
+ 2);
913 asm_emit_b(token
, 0x63 | (4 << 12), ops
, ops
+ 1, ops
+ 2);
916 asm_emit_b(token
, 0x63 | (5 << 12), ops
, ops
+ 1, ops
+ 2);
919 asm_emit_b(token
, 0x63 | (6 << 12), ops
, ops
+ 1, ops
+ 2);
922 asm_emit_b(token
, 0x63 | (7 << 12), ops
, ops
+ 1, ops
+ 2);
924 /* related pseudoinstructions */
926 asm_emit_b(token
, 0x63 | (4 << 12), ops
+ 1, ops
, ops
+ 2);
929 asm_emit_b(token
, 0x63 | (5 << 12), ops
+ 1, ops
, ops
+ 2);
932 asm_emit_b(token
, 0x63 | (6 << 12), ops
+ 1, ops
, ops
+ 2);
935 asm_emit_b(token
, 0x63 | (7 << 12), ops
+ 1, ops
, ops
+ 2);
940 asm_emit_r(token
, 0x33 | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
943 asm_emit_r(token
, 0x33 | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
946 asm_emit_r(token
, 0x3b | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
949 asm_emit_r(token
, 0x3b | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
952 asm_emit_r(token
, 0x33 | (1 << 25), ops
, ops
+ 1, ops
+ 2);
955 asm_emit_r(token
, 0x33 | (1 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
958 asm_emit_r(token
, 0x33 | (2 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
961 asm_emit_r(token
, 0x33 | (3 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
964 asm_emit_r(token
, 0x3b | (1 << 25), ops
, ops
+ 1, ops
+ 2);
967 asm_emit_r(token
, 0x33 | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
970 asm_emit_r(token
, 0x33 | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
973 asm_emit_r(token
, 0x3b | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
976 asm_emit_r(token
, 0x3b | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
979 /* Zicsr extension; (rd, csr, rs/uimm) */
981 asm_emit_i(token
, 0x73 | (3 << 12), ops
, ops
+ 2, ops
+ 1);
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);
989 asm_emit_i(token
, 0x73 | (2 << 12), ops
, ops
+ 2, ops
+ 1);
992 ops
[2].type
= OP_REG
;
993 asm_emit_i(token
, 0x73 | (6 << 12), ops
, ops
+ 2, ops
+ 1);
996 asm_emit_i(token
, 0x73 | (1 << 12), ops
, ops
+ 2, ops
+ 1);
999 ops
[2].type
= OP_REG
;
1000 asm_emit_i(token
, 0x73 | (5 << 12), ops
, ops
+ 2, ops
+ 1);
1004 /* register-based loads and stores (RD, RS1, IMM); CL-format */
1006 asm_emit_cl(token
, 1 << 13, ops
, ops
+ 1, ops
+ 2);
1008 case TOK_ASM_c_flw
: /* RV32FC-only */
1009 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
1012 asm_emit_cs(token
, 5 << 13, ops
, ops
+ 1, ops
+ 2);
1014 case TOK_ASM_c_fsw
: /* RV32FC-only */
1015 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
1018 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
1021 asm_emit_cl(token
, 2 << 13, ops
, ops
+ 1, ops
+ 2);
1024 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
1027 asm_emit_cs(token
, 6 << 13, ops
, ops
+ 1, ops
+ 2);
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
));
1042 if (rs2
->type
!= OP_REG
) {
1043 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token
, NULL
));
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
));
1051 uint16_t v
= imm
->e
.v
;
1052 /* S-type instruction:
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
)
1068 if (rs1
->type
!= OP_REG
) {
1069 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
1072 if (rs2
->type
!= OP_REG
) {
1073 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
1083 /* B-type instruction:
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
)
1098 case TOK_ASM_ebreak
:
1101 case TOK_ASM_fence_i
:
1106 asm_nullary_opcode(s1
, token
);
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
);
1120 asm_binary_opcode(s1
, token
);
1134 asm_mem_access_opcode(s1
, token
);
1138 asm_jalr_opcode(s1
, token
); /* it can be a pseudo instruction too*/
1141 asm_jal_opcode(s1
, token
); /* it can be a pseudo instruction too*/
1185 case TOK_ASM_mulhsu
:
1192 /* Zicsr extension */
1194 case TOK_ASM_csrrci
:
1196 case TOK_ASM_csrrsi
:
1198 case TOK_ASM_csrrwi
:
1199 asm_ternary_opcode(s1
, token
);
1203 case TOK_ASM_c_ebreak
:
1205 asm_nullary_opcode(s1
, token
);
1210 case TOK_ASM_c_jalr
:
1212 asm_unary_opcode(s1
, token
);
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
:
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
:
1232 case TOK_ASM_c_lwsp
:
1235 case TOK_ASM_c_sdsp
:
1236 case TOK_ASM_c_slli
:
1237 case TOK_ASM_c_srai
:
1238 case TOK_ASM_c_srli
:
1240 case TOK_ASM_c_subw
:
1241 case TOK_ASM_c_swsp
:
1243 asm_binary_opcode(s1
, token
);
1254 asm_ternary_opcode(s1
, token
);
1257 /* pseudoinstructions */
1260 asm_nullary_opcode(s1
, token
);
1266 asm_unary_opcode(s1
, token
);
1287 asm_binary_opcode(s1
, token
);
1294 asm_ternary_opcode(s1
, token
);
1298 expect("known instruction");
1302 static int asm_parse_csrvar(int t
)
1309 case TOK_ASM_fflags
:
1313 case TOK_ASM_instret
:
1317 case TOK_ASM_cycleh
:
1319 case TOK_ASM_instreth
:
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
,
1341 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1342 int nb_operands
, int nb_outputs
,
1343 const uint8_t *clobber_regs
,
1348 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1353 if (!strcmp(str
, "memory") ||
1354 !strcmp(str
, "cc") ||
1355 !strcmp(str
, "flags"))
1357 ts
= tok_alloc(str
, strlen(str
));
1358 reg
= asm_parse_regvar(ts
->tok
);
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
)
1372 return t
- TOK_ASM_x0
;
1374 if (t
< TOK_ASM_zero
)
1375 return t
- TOK_ASM_f0
;
1378 if (t
< TOK_ASM_ft0
)
1379 return t
- TOK_ASM_zero
;
1381 return t
- TOK_ASM_ft0
;
1384 /*************************************************************/
1387 /* caller: Add funct6, funct2 into opcode */
1388 static void asm_emit_ca(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
)
1392 if (rd
->type
!= OP_REG
) {
1393 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1397 if (rs2
->type
!= OP_REG
) {
1398 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1402 /* subtract index of x8 */
1406 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
1408 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1413 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1417 /* CA-type instruction:
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
)
1432 if (rs1
->type
!= OP_REG
) {
1433 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
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
));
1445 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
1452 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1456 /* CB-type instruction:
1463 /* non-branch also using CB:
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));
1477 gen_le16(opcode
| C_ENCODE_RS1(src
) | ((offset
& 0x1f) << 2) | (NTH_BIT(offset
, 5) << 12));
1482 static void asm_emit_ci(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
)
1486 if (rd
->type
!= OP_REG
) {
1487 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
1496 immediate
= imm
->e
.v
;
1498 /* CI-type instruction:
1506 case TOK_ASM_c_addi
:
1507 case TOK_ASM_c_addiw
:
1509 case TOK_ASM_c_slli
:
1510 gen_le16(opcode
| ((immediate
& 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
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));
1516 gen_le16(opcode
| (((immediate
>> 12) & 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 17) << 12));
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));
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));
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
)
1540 if (rd
->type
!= OP_REG
) {
1541 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
1553 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
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
));
1565 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token
, NULL
));
1569 /* CIW-type instruction:
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
)
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
));
1592 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
1596 /* CJ-type instruction:
1598 12...2 offset[11|4|9:8|10|6|7|3:1|5]
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
)
1610 if (rd
->type
!= OP_REG
) {
1611 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1615 if (rs1
->type
!= OP_REG
) {
1616 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
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
));
1629 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1634 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
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
));
1646 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1650 /* CL-type instruction:
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));
1667 gen_le16(opcode
| C_ENCODE_RS2(dst
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
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
));
1682 if (rs2
->type
!= OP_REG
) {
1683 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1687 /* CR-type instruction:
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
)
1702 if (rs2
->type
!= OP_REG
) {
1703 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1707 if (rs1
->type
!= OP_REG
) {
1708 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
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
));
1717 base
= rs1
->reg
- 8;
1721 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1726 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
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
));
1738 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1742 /* CS-type instruction:
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));
1758 gen_le16(opcode
| C_ENCODE_RS2(base
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
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
)
1770 if (rs2
->type
!= OP_REG
) {
1771 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
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
));
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
));
1788 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
1792 /* CSS-type instruction:
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));
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));
1810 expect("known instruction");
1814 /*************************************************************/
1815 #endif /* ndef TARGET_DEFS_ONLY */