1 /*************************************************************/
3 * RISCV64 assembler for TCC
7 #ifdef TARGET_DEFS_ONLY
10 /* 32 general purpose + 32 floating point registers */
11 #define NB_ASM_REGS 64
13 ST_FUNC
void g(int c
);
14 ST_FUNC
void gen_le16(int c
);
15 ST_FUNC
void gen_le32(int c
);
17 /*************************************************************/
19 /*************************************************************/
28 // Registers go from 0 to 31. We use next bit to choose general/float
29 #define REG_FLOAT_MASK 0x20
30 #define REG_IS_FLOAT(register_index) ((register_index) & REG_FLOAT_MASK)
31 #define REG_VALUE(register_index) ((register_index) & (REG_FLOAT_MASK-1))
32 #define C_ENCODE_RS1(register_index) (REG_VALUE(register_index) << 7)
33 #define C_ENCODE_RS2(register_index) (REG_VALUE(register_index) << 2)
34 #define ENCODE_RD(register_index) (REG_VALUE(register_index) << 7)
35 #define ENCODE_RS1(register_index) (REG_VALUE(register_index) << 15)
36 #define ENCODE_RS2(register_index) (REG_VALUE(register_index) << 20)
37 #define NTH_BIT(b, n) ((b >> n) & 1)
38 #define OP_IM12S (1 << OPT_IM12S)
39 #define OP_IM32 (1 << OPT_IM32)
40 #define OP_REG (1 << OPT_REG)
42 typedef struct Operand
{
51 static void asm_binary_opcode(TCCState
* s1
, int token
);
52 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
);
53 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
, int nb_operands
, int nb_outputs
, const uint8_t *clobber_regs
, int *pout_reg
);
54 static void asm_emit_b(int token
, uint32_t opcode
, const Operand
*rs1
, const Operand
*rs2
, const Operand
*imm
);
55 static void asm_emit_i(int token
, uint32_t opcode
, const Operand
*rd
, const Operand
*rs1
, const Operand
*rs2
);
56 static void asm_emit_j(int token
, uint32_t opcode
, const Operand
*rd
, const Operand
*rs2
);
57 static void asm_emit_opcode(uint32_t opcode
);
58 static void asm_emit_r(int token
, uint32_t opcode
, const Operand
*rd
, const Operand
*rs1
, const Operand
*rs2
);
59 static void asm_emit_s(int token
, uint32_t opcode
, const Operand
*rs1
, const Operand
*rs2
, const Operand
*imm
);
60 static void asm_emit_u(int token
, uint32_t opcode
, const Operand
*rd
, const Operand
*rs2
);
61 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
, int nb_outputs
, int is_output
, uint8_t *clobber_regs
, int out_reg
);
62 static void asm_nullary_opcode(TCCState
*s1
, int token
);
63 ST_FUNC
void asm_opcode(TCCState
*s1
, int token
);
64 static int asm_parse_csrvar(int t
);
65 ST_FUNC
int asm_parse_regvar(int t
);
66 static void asm_ternary_opcode(TCCState
*s1
, int token
);
67 static void asm_unary_opcode(TCCState
*s1
, int token
);
68 ST_FUNC
void gen_expr32(ExprValue
*pe
);
69 static void parse_operand(TCCState
*s1
, Operand
*op
);
70 static void parse_operands(TCCState
*s1
, Operand
*ops
, int count
);
71 static void parse_mem_access_operands(TCCState
*s1
, Operand
* ops
);
72 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
);
74 static void asm_emit_ca(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
);
75 static void asm_emit_cb(int token
, uint16_t opcode
, const Operand
*rs1
, const Operand
*imm
);
76 static void asm_emit_ci(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
);
77 static void asm_emit_ciw(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
);
78 static void asm_emit_cj(int token
, uint16_t opcode
, const Operand
*imm
);
79 static void asm_emit_cl(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs1
, const Operand
*imm
);
80 static void asm_emit_cr(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
);
81 static void asm_emit_cs(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*rs1
, const Operand
*imm
);
82 static void asm_emit_css(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*imm
);
84 /* XXX: make it faster ? */
91 if (ind1
> cur_text_section
->data_allocated
)
92 section_realloc(cur_text_section
, ind1
);
93 cur_text_section
->data
[ind
] = c
;
97 ST_FUNC
void gen_le16 (int i
)
103 ST_FUNC
void gen_le32 (int i
)
109 if (ind1
> cur_text_section
->data_allocated
)
110 section_realloc(cur_text_section
, ind1
);
111 cur_text_section
->data
[ind
++] = i
& 0xFF;
112 cur_text_section
->data
[ind
++] = (i
>> 8) & 0xFF;
113 cur_text_section
->data
[ind
++] = (i
>> 16) & 0xFF;
114 cur_text_section
->data
[ind
++] = (i
>> 24) & 0xFF;
117 ST_FUNC
void gen_expr32(ExprValue
*pe
)
122 static void asm_emit_opcode(uint32_t opcode
) {
126 static void asm_nullary_opcode(TCCState
*s1
, int token
)
128 static const Operand nil
= {.type
= OP_REG
};
129 static const Operand zimm
= {.type
= OP_IM12S
};
134 case TOK_ASM_fence
: // I
135 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
137 case TOK_ASM_fence_i
: // I
138 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
143 case TOK_ASM_ecall
: // I (pseudo)
144 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
146 case TOK_ASM_ebreak
: // I (pseudo)
147 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
153 asm_emit_i(token
, (4 << 2) | 3, &nil
, &nil
, &zimm
);
157 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
160 /* Pseudoinstructions */
162 /* jalr zero, x1, 0 */
163 asm_emit_opcode( 0x67 | (0 << 12) | ENCODE_RS1(1) );
167 case TOK_ASM_c_ebreak
:
168 asm_emit_cr(token
, 2 | (9 << 12), &nil
, &nil
);
171 asm_emit_ci(token
, 1, &nil
, &zimm
);
175 expect("nullary instruction");
179 /* Parse a text containing operand and store the result in OP */
180 static void parse_operand(TCCState
*s1
, Operand
*op
)
188 if ((reg
= asm_parse_regvar(tok
)) != -1) {
189 next(); // skip register name
191 op
->reg
= (uint8_t) reg
;
193 } else if (tok
== '$') {
195 next(); // skip '#' or '$'
196 } else if ((e
.v
= asm_parse_csrvar(tok
)) != -1) {
203 /* compare against unsigned 12-bit maximum */
205 if ((int) op
->e
.v
>= -0x1000 && (int) op
->e
.v
< 0x1000)
207 } else if (op
->e
.sym
->type
.t
& (VT_EXTERN
| VT_STATIC
)) {
208 label
.type
.t
= VT_VOID
| VT_STATIC
;
210 /* use the medium PIC model: GOT, auipc, lw */
211 if (op
->e
.sym
->type
.t
& VT_STATIC
)
212 greloca(cur_text_section
, op
->e
.sym
, ind
, R_RISCV_PCREL_HI20
, 0);
214 greloca(cur_text_section
, op
->e
.sym
, ind
, R_RISCV_GOT_HI20
, 0);
215 put_extern_sym(&label
, cur_text_section
, ind
, 0);
216 greloca(cur_text_section
, &label
, ind
+4, R_RISCV_PCREL_LO12_I
, 0);
225 static void parse_operands(TCCState
*s1
, Operand
* ops
, int count
){
227 for (i
= 0; i
< count
; i
++) {
234 parse_operand(s1
, &ops
[i
]);
238 /* parse `X, imm(Y)` to {X, Y, imm} operands */
239 static void parse_mem_access_operands(TCCState
*s1
, Operand
* ops
){
240 static const Operand zimm
= {.type
= OP_IM12S
};
244 parse_operand(s1
, &ops
[0]);
253 parse_operand(s1
, &ops
[1]);
254 if ( tok
== ')') next(); else expect("')'");
257 parse_operand(s1
, &ops
[2]);
259 /* `X, imm(Y)` case*/
261 parse_operand(s1
, &ops
[1]);
262 if ( tok
== ')') next(); else expect("')'");
265 /* we parsed Y thinking it was imm, swap and default imm to zero */
274 /* This is special: First operand is optional */
275 static void asm_jal_opcode(TCCState
*s1
, int token
){
276 static const Operand ra
= {.type
= OP_REG
, .reg
= 1};
278 parse_operand(s1
, &ops
[0]);
279 if ( ops
[0].type
!= OP_REG
) {
280 /* no more operands, it's the pseudoinstruction:
293 parse_operand(s1
, &ops
[1]);
295 if (ops
[1].e
.sym
&& ops
[1].e
.sym
->type
.t
& (VT_EXTERN
| VT_STATIC
)){
296 greloca(cur_text_section
, ops
[1].e
.sym
, ind
, R_RISCV_JAL
, 0);
298 asm_emit_j(token
, 0x6f, &ops
[0], &ops
[1]);
301 /* This is special: It can be a pseudointruction or a instruction */
302 static void asm_jalr_opcode(TCCState
*s1
, int token
){
303 static const Operand zimm
= {.type
= OP_IM12S
};
304 static const Operand ra
= {.type
= OP_REG
, .reg
= 1};
308 parse_operand(s1
, &ops
[0]);
312 /* no more operands, it's the pseudoinstruction:
317 asm_emit_i(token
, 0x67 | (0 << 12), &ra
, &ops
[0], &zimm
);
324 parse_operand(s1
, &ops
[1]);
325 if ( tok
== ')') next(); else expect("')'");
328 parse_operand(s1
, &ops
[2]);
330 /* `X, imm(Y)` case*/
332 parse_operand(s1
, &ops
[1]);
333 if ( tok
== ')') next(); else expect("')'");
336 /* we parsed Y thinking it was imm, swap and default imm to zero */
343 /* jalr(RD, RS1, IMM); I-format */
344 asm_emit_i(token
, 0x67 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
348 static void asm_unary_opcode(TCCState
*s1
, int token
)
350 uint32_t opcode
= (0x1C << 2) | 3 | (2 << 12);
352 static const Operand zero
= {.type
= OP_REG
};
353 static const Operand zimm
= {.type
= OP_IM12S
};
355 parse_operands(s1
, &op
, 1);
356 /* Note: Those all map to CSR--so they are pseudo-instructions. */
357 opcode
|= ENCODE_RD(op
.reg
);
360 /* pseudoinstructions */
361 case TOK_ASM_rdcycle
:
362 asm_emit_opcode(opcode
| (0xC00 << 20));
364 case TOK_ASM_rdcycleh
:
365 asm_emit_opcode(opcode
| (0xC80 << 20));
368 asm_emit_opcode(opcode
| (0xC01 << 20) | ENCODE_RD(op
.reg
));
370 case TOK_ASM_rdtimeh
:
371 asm_emit_opcode(opcode
| (0xC81 << 20) | ENCODE_RD(op
.reg
));
373 case TOK_ASM_rdinstret
:
374 asm_emit_opcode(opcode
| (0xC02 << 20) | ENCODE_RD(op
.reg
));
376 case TOK_ASM_rdinstreth
:
377 asm_emit_opcode(opcode
| (0xC82 << 20) | ENCODE_RD(op
.reg
));
381 /* jalr zero, 0(rs)*/
382 asm_emit_i(token
, 0x67 | (0 << 12), &zero
, &op
, &zimm
);
386 greloca(cur_text_section
, op
.e
.sym
, ind
, R_RISCV_CALL
, 0);
387 asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(1));
388 /* jalr zero, 0(ra) */
389 asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(1));
393 greloca(cur_text_section
, op
.e
.sym
, ind
, R_RISCV_CALL
, 0);
394 asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(6));
395 /* jalr zero, 0(x6) */
396 asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(6));
401 asm_emit_cj(token
, 1 | (5 << 13), &op
);
403 case TOK_ASM_c_jal
: /* RV32C-only */
404 asm_emit_cj(token
, 1 | (1 << 13), &op
);
407 asm_emit_cr(token
, 2 | (9 << 12), &op
, &zero
);
410 asm_emit_cr(token
, 2 | (8 << 12), &op
, &zero
);
413 expect("unary instruction");
417 static void asm_emit_u(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs2
)
419 if (rd
->type
!= OP_REG
) {
420 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
423 if (rs2
->type
!= OP_IM12S
&& rs2
->type
!= OP_IM32
) {
424 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token
, NULL
));
426 } else if (rs2
->e
.v
>= 0x100000) {
427 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0xfffff", get_tok_str(token
, NULL
));
430 /* U-type instruction:
434 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | (rs2
->e
.v
<< 12));
437 static void asm_binary_opcode(TCCState
* s1
, int token
)
439 static const Operand zero
= {.type
= OP_REG
, .reg
= 0};
440 Operand imm
= {.type
= OP_IM12S
, .e
= {.v
= 0}};
445 parse_operands(s1
, &ops
[0], 2);
448 asm_emit_u(token
, (0xD << 2) | 3, &ops
[0], &ops
[1]);
451 asm_emit_u(token
, (0x05 << 2) | 3, &ops
[0], &ops
[1]);
456 asm_emit_cr(token
, 2 | (9 << 12), ops
, ops
+ 1);
459 asm_emit_cr(token
, 2 | (8 << 12), ops
, ops
+ 1);
462 case TOK_ASM_c_addi16sp
:
463 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
466 asm_emit_ci(token
, 1, ops
, ops
+ 1);
468 case TOK_ASM_c_addiw
:
469 asm_emit_ci(token
, 1 | (1 << 13), ops
, ops
+ 1);
471 case TOK_ASM_c_fldsp
:
472 asm_emit_ci(token
, 2 | (1 << 13), ops
, ops
+ 1);
474 case TOK_ASM_c_flwsp
: /* RV32FC-only */
475 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
478 asm_emit_ci(token
, 2 | (3 << 13), ops
, ops
+ 1);
481 asm_emit_ci(token
, 1 | (2 << 13), ops
, ops
+ 1);
484 asm_emit_ci(token
, 1 | (3 << 13), ops
, ops
+ 1);
487 asm_emit_ci(token
, 2 | (2 << 13), ops
, ops
+ 1);
490 asm_emit_ci(token
, 2, ops
, ops
+ 1);
493 case TOK_ASM_c_addi4spn
:
494 asm_emit_ciw(token
, 0, ops
, ops
+ 1);
497 #define CA (1 | (3 << 10) | (4 << 13))
499 asm_emit_ca(token
, CA
| (1 << 5) | (1 << 12), ops
, ops
+ 1);
502 asm_emit_ca(token
, CA
| (3 << 5), ops
, ops
+ 1);
505 asm_emit_ca(token
, CA
| (2 << 5), ops
, ops
+ 1);
508 asm_emit_ca(token
, CA
, ops
, ops
+ 1);
511 asm_emit_ca(token
, CA
| (1 << 12), ops
, ops
+ 1);
514 asm_emit_ca(token
, CA
| (1 << 5), ops
, ops
+ 1);
519 asm_emit_cb(token
, 1 | (2 << 10) | (4 << 13), ops
, ops
+ 1);
522 asm_emit_cb(token
, 1 | (6 << 13), ops
, ops
+ 1);
525 asm_emit_cb(token
, 1 | (7 << 13), ops
, ops
+ 1);
528 asm_emit_cb(token
, 1 | (1 << 10) | (4 << 13), ops
, ops
+ 1);
531 asm_emit_cb(token
, 1 | (4 << 13), ops
, ops
+ 1);
535 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
538 asm_emit_css(token
, 2 | (6 << 13), ops
, ops
+ 1);
540 case TOK_ASM_c_fswsp
: /* RV32FC-only */
541 asm_emit_css(token
, 2 | (7 << 13), ops
, ops
+ 1);
543 case TOK_ASM_c_fsdsp
:
544 asm_emit_css(token
, 2 | (5 << 13), ops
, ops
+ 1);
547 /* pseudoinstructions */
551 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
553 asm_emit_i(token
, 3 | (2 << 12), ops
, ops
, ops
+ 1);
557 asm_emit_u(token
, 3 | (5 << 2), ops
, ops
+ 1);
559 asm_emit_i(token
, 3 | (4 << 2), ops
, ops
, ops
+ 1);
562 if(ops
[1].type
!= OP_IM32
&& ops
[1].type
!= OP_IM12S
){
563 tcc_error("'%s': Expected first source operand that is an immediate value between 0 and 0xFFFFFFFFFFFFFFFF", get_tok_str(token
, NULL
));
566 hi
= (int64_t)ops
[1].e
.v
>> 32;
570 imm
.e
.v
= ((hi
+ 0x800) & 0xfffff000) >> 12;
571 /* lui rd, HI_20(HI_32(imm)) */
572 asm_emit_u(token
, (0xD << 2) | 3, &ops
[0], &imm
);
573 /* addi rd, rd, LO_12(HI_32(imm)) */
574 imm
.e
.v
= (int32_t)hi
<<20>>20;
575 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[0], &imm
);
576 /* slli rd, rd, 12 */
578 asm_emit_i(token
, (4 << 2) | 3 | (1 << 12), &ops
[0], &ops
[0], &imm
);
579 /* addi rd, rd, HI_12(LO_32(imm)) */
580 imm
.e
.v
= (lo
+ (1<<19)) >> 20;
581 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[0], &imm
);
582 /* slli rd, rd, 12 */
584 asm_emit_i(token
, (4 << 2) | 3 | (1 << 12), &ops
[0], &ops
[0], &imm
);
585 /* addi rd, rd, HI_12(LO_20(LO_32imm)) */
588 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[0], &imm
);
591 asm_emit_i(token
, (4 << 2) | 3 | (1 << 12), &ops
[0], &ops
[0], &imm
);
592 /* addi rd, rd, LO_8(LO_20(LO_32imm)) */
594 imm
.e
.v
= lo
<< 20 >> 20;
595 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[0], &imm
);
599 asm_emit_i(token
, 3 | (4 << 2), &ops
[0], &ops
[1], &imm
);
602 /* xori rd, rs, -1 */
604 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &imm
);
609 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &zero
, &imm
);
614 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &zero
, &imm
);
618 asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(5));
619 greloca(cur_text_section
, ops
->e
.sym
, ind
, R_RISCV_CALL
, 0);
620 /* jalr zero, 0(x5) */
621 asm_emit_opcode(0x67 | (0 << 12) | ENCODE_RS1(5));
624 /* sltiu rd, rs, 1 */
626 asm_emit_i(token
, (0x4 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &imm
);
629 /* sltu rd, zero, rs */
631 asm_emit_r(token
, (0xC << 2) | 3 | (3 << 12), &ops
[0], &zero
, &ops
[1]);
634 /* slt rd, rs, zero */
635 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &zero
);
638 /* slt rd, zero, rs */
639 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &zero
, &ops
[1]);
642 /* bne rs, zero, offset */
643 asm_emit_b(token
, 0x63 | (1 << 12), &ops
[0], &zero
, &ops
[1]);
646 /* bne rs, zero, offset */
647 asm_emit_b(token
, 0x63 | (0 << 12), &ops
[0], &zero
, &ops
[1]);
650 /* bge rs, zero, offset */
651 asm_emit_b(token
, 0x63 | (5 << 12), &ops
[0], &zero
, &ops
[1]);
654 /* bge zero, rs, offset */
655 asm_emit_b(token
, 0x63 | (5 << 12), &zero
, &ops
[0], &ops
[1]);
658 /* blt rs, zero, offset */
659 asm_emit_b(token
, 0x63 | (4 << 12), &ops
[0], &zero
, &ops
[1]);
662 /* blt zero, rs, offset */
663 asm_emit_b(token
, 0x63 | (4 << 12), &zero
, &ops
[0], &ops
[1]);
667 expect("binary instruction");
671 /* caller: Add funct3, funct7 into opcode */
672 static void asm_emit_r(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs1
, const Operand
* rs2
)
674 if (rd
->type
!= OP_REG
) {
675 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
678 if (rs1
->type
!= OP_REG
) {
679 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
682 if (rs2
->type
!= OP_REG
) {
683 tcc_error("'%s': Expected second source operand that is a register or immediate", get_tok_str(token
, NULL
));
686 /* R-type instruction:
693 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | ENCODE_RS1(rs1
->reg
) | ENCODE_RS2(rs2
->reg
));
696 /* caller: Add funct3 into opcode */
697 static void asm_emit_i(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs1
, const Operand
* rs2
)
699 if (rd
->type
!= OP_REG
) {
700 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
703 if (rs1
->type
!= OP_REG
) {
704 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
707 if (rs2
->type
!= OP_IM12S
) {
708 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token
, NULL
));
711 /* I-type instruction:
718 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | ENCODE_RS1(rs1
->reg
) | (rs2
->e
.v
<< 20));
721 static void asm_emit_j(int token
, uint32_t opcode
, const Operand
* rd
, const Operand
* rs2
)
725 if (rd
->type
!= OP_REG
) {
726 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
729 if (rs2
->type
!= OP_IM12S
&& rs2
->type
!= OP_IM32
) {
730 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token
, NULL
));
736 /* even offsets in a +- 1 MiB range */
737 if ((int)imm
> (1 << 20) -1 || (int)imm
<= -1 * ((1 << 20) -1)) {
738 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0x1fffff", get_tok_str(token
, NULL
));
743 tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token
, NULL
));
746 /* J-type instruction:
753 gen_le32(opcode
| ENCODE_RD(rd
->reg
) | (((imm
>> 20) & 1) << 31) | (((imm
>> 1) & 0x3ff) << 21) | (((imm
>> 11) & 1) << 20) | (((imm
>> 12) & 0xff) << 12));
756 static void asm_mem_access_opcode(TCCState
*s1
, int token
)
760 parse_mem_access_operands(s1
, &ops
[0]);
762 /* Pseudoinstruction: inst reg, label
766 * And with the proper relocation to label
768 if (ops
[1].type
== OP_IM32
&& ops
[1].e
.sym
&& ops
[1].e
.sym
->type
.t
& VT_STATIC
){
770 /* set the offset to zero */
771 ops
[2].type
= OP_IM12S
;
774 asm_emit_u(token
, (0x05 << 2) | 3, &ops
[0], &ops
[2]);
778 // l{b|h|w|d}[u] rd, imm(rs1); I-format
780 asm_emit_i(token
, (0x0 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
783 asm_emit_i(token
, (0x0 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
786 asm_emit_i(token
, (0x0 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
789 asm_emit_i(token
, (0x0 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
792 asm_emit_i(token
, (0x0 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
795 asm_emit_i(token
, (0x0 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
798 asm_emit_i(token
, (0x0 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
801 // s{b|h|w|d} rs2, imm(rs1); S-format (with rsX swapped)
803 asm_emit_s(token
, (0x8 << 2) | 3 | (0 << 12), &ops
[1], &ops
[0], &ops
[2]);
806 asm_emit_s(token
, (0x8 << 2) | 3 | (1 << 12), &ops
[1], &ops
[0], &ops
[2]);
809 asm_emit_s(token
, (0x8 << 2) | 3 | (2 << 12), &ops
[1], &ops
[0], &ops
[2]);
812 asm_emit_s(token
, (0x8 << 2) | 3 | (3 << 12), &ops
[1], &ops
[0], &ops
[2]);
817 static void asm_ternary_opcode(TCCState
*s1
, int token
)
820 parse_operands(s1
, &ops
[0], 3);
824 asm_emit_r(token
, (0xC << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
827 asm_emit_i(token
, (4 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
830 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
833 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
836 asm_emit_r(token
, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
839 asm_emit_i(token
, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops
[0], &ops
[1], &ops
[2]);
842 asm_emit_r(token
, (0xE << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
845 asm_emit_i(token
, (6 << 2) | 3 | (1 << 12), &ops
[0], &ops
[1], &ops
[2]);
848 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
851 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
854 asm_emit_r(token
, (0xE << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
857 asm_emit_i(token
, (0x6 << 2) | 3 | (5 << 12), &ops
[0], &ops
[1], &ops
[2]);
860 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
863 asm_emit_r(token
, (0xC << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
866 asm_emit_i(token
, (4 << 2) | 3, &ops
[0], &ops
[1], &ops
[2]);
869 asm_emit_r(token
, (0xC << 2) | 3 | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
872 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
874 case TOK_ASM_addiw
: // 64 bit
875 asm_emit_i(token
, (0x6 << 2) | 3 | (0 << 12), &ops
[0], &ops
[1], &ops
[2]);
878 asm_emit_r(token
, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops
[0], &ops
[1], &ops
[2]);
881 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
884 asm_emit_r(token
, (0xC << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
887 asm_emit_i(token
, (0x4 << 2) | 3 | (4 << 12), &ops
[0], &ops
[1], &ops
[2]);
890 asm_emit_r(token
, (0xC << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
893 asm_emit_i(token
, (0x4 << 2) | 3 | (6 << 12), &ops
[0], &ops
[1], &ops
[2]);
896 asm_emit_r(token
, (0xC << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
899 asm_emit_i(token
, (0x4 << 2) | 3 | (7 << 12), &ops
[0], &ops
[1], &ops
[2]);
902 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
905 asm_emit_r(token
, (0xC << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
908 asm_emit_i(token
, (0x4 << 2) | 3 | (2 << 12), &ops
[0], &ops
[1], &ops
[2]);
911 asm_emit_r(token
, (0xC << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
914 asm_emit_i(token
, (0x4 << 2) | 3 | (3 << 12), &ops
[0], &ops
[1], &ops
[2]);
917 /* branch (RS1, RS2, IMM); B-format */
919 asm_emit_b(token
, 0x63 | (0 << 12), ops
, ops
+ 1, ops
+ 2);
922 asm_emit_b(token
, 0x63 | (1 << 12), ops
, ops
+ 1, ops
+ 2);
925 asm_emit_b(token
, 0x63 | (4 << 12), ops
, ops
+ 1, ops
+ 2);
928 asm_emit_b(token
, 0x63 | (5 << 12), ops
, ops
+ 1, ops
+ 2);
931 asm_emit_b(token
, 0x63 | (6 << 12), ops
, ops
+ 1, ops
+ 2);
934 asm_emit_b(token
, 0x63 | (7 << 12), ops
, ops
+ 1, ops
+ 2);
936 /* related pseudoinstructions */
938 asm_emit_b(token
, 0x63 | (4 << 12), ops
+ 1, ops
, ops
+ 2);
941 asm_emit_b(token
, 0x63 | (5 << 12), ops
+ 1, ops
, ops
+ 2);
944 asm_emit_b(token
, 0x63 | (6 << 12), ops
+ 1, ops
, ops
+ 2);
947 asm_emit_b(token
, 0x63 | (7 << 12), ops
+ 1, ops
, ops
+ 2);
952 asm_emit_r(token
, 0x33 | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
955 asm_emit_r(token
, 0x33 | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
958 asm_emit_r(token
, 0x3b | (5 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
961 asm_emit_r(token
, 0x3b | (4 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
964 asm_emit_r(token
, 0x33 | (1 << 25), ops
, ops
+ 1, ops
+ 2);
967 asm_emit_r(token
, 0x33 | (1 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
970 asm_emit_r(token
, 0x33 | (2 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
973 asm_emit_r(token
, 0x33 | (3 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
976 asm_emit_r(token
, 0x3b | (1 << 25), ops
, ops
+ 1, ops
+ 2);
979 asm_emit_r(token
, 0x33 | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
982 asm_emit_r(token
, 0x33 | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
985 asm_emit_r(token
, 0x3b | (7 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
988 asm_emit_r(token
, 0x3b | (6 << 12) | (1 << 25), ops
, ops
+ 1, ops
+ 2);
991 /* Zicsr extension; (rd, csr, rs/uimm) */
993 asm_emit_i(token
, 0x73 | (3 << 12), ops
, ops
+ 2, ops
+ 1);
996 /* using rs1 field for uimmm */
997 ops
[2].type
= OP_REG
;
998 asm_emit_i(token
, 0x73 | (7 << 12), ops
, ops
+ 2, ops
+ 1);
1001 asm_emit_i(token
, 0x73 | (2 << 12), ops
, ops
+ 2, ops
+ 1);
1003 case TOK_ASM_csrrsi
:
1004 ops
[2].type
= OP_REG
;
1005 asm_emit_i(token
, 0x73 | (6 << 12), ops
, ops
+ 2, ops
+ 1);
1008 asm_emit_i(token
, 0x73 | (1 << 12), ops
, ops
+ 2, ops
+ 1);
1010 case TOK_ASM_csrrwi
:
1011 ops
[2].type
= OP_REG
;
1012 asm_emit_i(token
, 0x73 | (5 << 12), ops
, ops
+ 2, ops
+ 1);
1016 /* register-based loads and stores (RD, RS1, IMM); CL-format */
1018 asm_emit_cl(token
, 1 << 13, ops
, ops
+ 1, ops
+ 2);
1020 case TOK_ASM_c_flw
: /* RV32FC-only */
1021 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
1024 asm_emit_cs(token
, 5 << 13, ops
, ops
+ 1, ops
+ 2);
1026 case TOK_ASM_c_fsw
: /* RV32FC-only */
1027 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
1030 asm_emit_cl(token
, 3 << 13, ops
, ops
+ 1, ops
+ 2);
1033 asm_emit_cl(token
, 2 << 13, ops
, ops
+ 1, ops
+ 2);
1036 asm_emit_cs(token
, 7 << 13, ops
, ops
+ 1, ops
+ 2);
1039 asm_emit_cs(token
, 6 << 13, ops
, ops
+ 1, ops
+ 2);
1043 expect("ternary instruction");
1047 /* caller: Add funct3 to opcode */
1048 static void asm_emit_s(int token
, uint32_t opcode
, const Operand
* rs1
, const Operand
* rs2
, const Operand
* imm
)
1050 if (rs1
->type
!= OP_REG
) {
1051 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
1054 if (rs2
->type
!= OP_REG
) {
1055 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token
, NULL
));
1058 if (imm
->type
!= OP_IM12S
) {
1059 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token
, NULL
));
1063 uint16_t v
= imm
->e
.v
;
1064 /* S-type instruction:
1071 opcode always fixed pos. */
1072 gen_le32(opcode
| ENCODE_RS1(rs1
->reg
) | ENCODE_RS2(rs2
->reg
) | ((v
& 0x1F) << 7) | ((v
>> 5) << 25));
1076 static void asm_emit_b(int token
, uint32_t opcode
, const Operand
*rs1
, const Operand
*rs2
, const Operand
*imm
)
1080 if (rs1
->type
!= OP_REG
) {
1081 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token
, NULL
));
1084 if (rs2
->type
!= OP_REG
) {
1085 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1088 if (imm
->type
!= OP_IM12S
) {
1089 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token
, NULL
));
1095 /* B-type instruction:
1104 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));
1107 ST_FUNC
void asm_opcode(TCCState
*s1
, int token
)
1110 case TOK_ASM_ebreak
:
1113 case TOK_ASM_fence_i
:
1118 asm_nullary_opcode(s1
, token
);
1121 case TOK_ASM_rdcycle
:
1122 case TOK_ASM_rdcycleh
:
1123 case TOK_ASM_rdtime
:
1124 case TOK_ASM_rdtimeh
:
1125 case TOK_ASM_rdinstret
:
1126 case TOK_ASM_rdinstreth
:
1127 asm_unary_opcode(s1
, token
);
1132 asm_binary_opcode(s1
, token
);
1146 asm_mem_access_opcode(s1
, token
);
1150 asm_jalr_opcode(s1
, token
); /* it can be a pseudo instruction too*/
1153 asm_jal_opcode(s1
, token
); /* it can be a pseudo instruction too*/
1197 case TOK_ASM_mulhsu
:
1204 /* Zicsr extension */
1206 case TOK_ASM_csrrci
:
1208 case TOK_ASM_csrrsi
:
1210 case TOK_ASM_csrrwi
:
1211 asm_ternary_opcode(s1
, token
);
1215 case TOK_ASM_c_ebreak
:
1217 asm_nullary_opcode(s1
, token
);
1222 case TOK_ASM_c_jalr
:
1224 asm_unary_opcode(s1
, token
);
1228 case TOK_ASM_c_addi16sp
:
1229 case TOK_ASM_c_addi4spn
:
1230 case TOK_ASM_c_addi
:
1231 case TOK_ASM_c_addiw
:
1232 case TOK_ASM_c_addw
:
1234 case TOK_ASM_c_andi
:
1235 case TOK_ASM_c_beqz
:
1236 case TOK_ASM_c_bnez
:
1237 case TOK_ASM_c_fldsp
:
1238 case TOK_ASM_c_flwsp
:
1239 case TOK_ASM_c_fsdsp
:
1240 case TOK_ASM_c_fswsp
:
1241 case TOK_ASM_c_ldsp
:
1244 case TOK_ASM_c_lwsp
:
1247 case TOK_ASM_c_sdsp
:
1248 case TOK_ASM_c_slli
:
1249 case TOK_ASM_c_srai
:
1250 case TOK_ASM_c_srli
:
1252 case TOK_ASM_c_subw
:
1253 case TOK_ASM_c_swsp
:
1255 asm_binary_opcode(s1
, token
);
1266 asm_ternary_opcode(s1
, token
);
1269 /* pseudoinstructions */
1272 asm_nullary_opcode(s1
, token
);
1278 asm_unary_opcode(s1
, token
);
1299 asm_binary_opcode(s1
, token
);
1306 asm_ternary_opcode(s1
, token
);
1310 expect("known instruction");
1314 static int asm_parse_csrvar(int t
)
1321 case TOK_ASM_fflags
:
1325 case TOK_ASM_instret
:
1329 case TOK_ASM_cycleh
:
1331 case TOK_ASM_instreth
:
1340 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
)
1346 if ((r
& VT_VALMASK
) == VT_CONST
) {
1347 if (!(r
& VT_LVAL
) && modifier
!= 'c' && modifier
!= 'n' &&
1349 //cstr_ccat(add_str, '#');
1352 const char *name
= get_tok_str(sv
->sym
->v
, NULL
);
1353 if (sv
->sym
->v
>= SYM_FIRST_ANOM
) {
1354 /* In case of anonymous symbols ("L.42", used
1355 for static data labels) we can't find them
1356 in the C symbol table when later looking up
1357 this name. So enter them now into the asm label
1358 list when we still know the symbol. */
1359 get_asm_sym(tok_alloc(name
, strlen(name
))->tok
, sv
->sym
);
1361 if (tcc_state
->leading_underscore
)
1362 cstr_ccat(add_str
, '_');
1363 cstr_cat(add_str
, name
, -1);
1364 if ((uint32_t) sv
->c
.i
== 0)
1366 cstr_ccat(add_str
, '+');
1369 if (modifier
== 'n')
1371 if (modifier
== 'z' && sv
->c
.i
== 0) {
1372 cstr_cat(add_str
, "zero", -1);
1374 snprintf(buf
, sizeof(buf
), "%d", (int) sv
->c
.i
);
1375 cstr_cat(add_str
, buf
, -1);
1378 } else if ((r
& VT_VALMASK
) == VT_LOCAL
) {
1379 snprintf(buf
, sizeof(buf
), "%d", (int) sv
->c
.i
);
1380 cstr_cat(add_str
, buf
, -1);
1381 } else if (r
& VT_LVAL
) {
1382 reg
= r
& VT_VALMASK
;
1383 if (reg
>= VT_CONST
)
1384 tcc_internal_error("");
1385 if ((sv
->type
.t
& VT_BTYPE
) == VT_FLOAT
||
1386 (sv
->type
.t
& VT_BTYPE
) == VT_DOUBLE
) {
1387 /* floating point register */
1388 reg
= TOK_ASM_f0
+ reg
;
1390 /* general purpose register */
1391 reg
= TOK_ASM_x0
+ reg
;
1393 snprintf(buf
, sizeof(buf
), "%s", get_tok_str(reg
, NULL
));
1394 cstr_cat(add_str
, buf
, -1);
1397 reg
= r
& VT_VALMASK
;
1398 if (reg
>= VT_CONST
)
1399 tcc_internal_error("");
1400 if ((sv
->type
.t
& VT_BTYPE
) == VT_FLOAT
||
1401 (sv
->type
.t
& VT_BTYPE
) == VT_DOUBLE
) {
1402 /* floating point register */
1403 reg
= TOK_ASM_f0
+ reg
;
1405 /* general purpose register */
1406 reg
= TOK_ASM_x0
+ reg
;
1408 snprintf(buf
, sizeof(buf
), "%s", get_tok_str(reg
, NULL
));
1409 cstr_cat(add_str
, buf
, -1);
1413 /* TCC does not use RISC-V register numbers internally, it uses 0-8 for
1414 * integers and 8-16 for floats instead */
1415 static int tcc_ireg(int r
){
1416 return REG_VALUE(r
) - 10;
1418 static int tcc_freg(int r
){
1419 return REG_VALUE(r
) - 10 + 8;
1422 /* generate prolog and epilog code for asm statement */
1423 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
,
1424 int nb_outputs
, int is_output
,
1425 uint8_t *clobber_regs
,
1428 uint8_t regs_allocated
[NB_ASM_REGS
];
1432 static const uint8_t reg_saved
[] = {
1433 // General purpose regs
1434 8, 9, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
1436 40, 41, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59
1439 /* mark all used registers */
1440 memcpy(regs_allocated
, clobber_regs
, sizeof(regs_allocated
));
1441 for(i
= 0; i
< nb_operands
; i
++) {
1444 regs_allocated
[op
->reg
] = 1;
1449 /* generate reg save code */
1450 for(i
= 0; i
< sizeof(reg_saved
)/sizeof(reg_saved
[0]); i
++) {
1452 if (regs_allocated
[reg
]) {
1454 /* addi sp, sp, -offset */
1455 gen_le32((4 << 2) | 3 |
1456 ENCODE_RD(2) | ENCODE_RS1(2) | -8 << 20);
1457 if (REG_IS_FLOAT(reg
)){
1458 /* fsd reg, offset(sp) */
1459 gen_le32( 0x27 | (3 << 12) |
1460 ENCODE_RS2(reg
) | ENCODE_RS1(2) );
1462 /* sd reg, offset(sp) */
1463 gen_le32((0x8 << 2) | 3 | (3 << 12) |
1464 ENCODE_RS2(reg
) | ENCODE_RS1(2) );
1469 /* generate load code */
1470 for(i
= 0; i
< nb_operands
; i
++) {
1473 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1475 /* memory reference case (for both input and
1479 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
| VT_LVAL
;
1481 load(tcc_ireg(op
->reg
), &sv
);
1482 } else if (i
>= nb_outputs
|| op
->is_rw
) {
1483 /* load value in register */
1484 if ((op
->vt
->type
.t
& VT_BTYPE
) == VT_FLOAT
||
1485 (op
->vt
->type
.t
& VT_BTYPE
) == VT_DOUBLE
) {
1486 load(tcc_freg(op
->reg
), op
->vt
);
1488 load(tcc_ireg(op
->reg
), op
->vt
);
1491 tcc_error("long long not implemented");
1497 /* generate save code */
1498 for(i
= 0 ; i
< nb_outputs
; i
++) {
1501 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1502 if (!op
->is_memory
) {
1505 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
;
1507 load(tcc_ireg(out_reg
), &sv
);
1510 sv
.r
= (sv
.r
& ~VT_VALMASK
) | out_reg
;
1511 store(tcc_ireg(op
->reg
), &sv
);
1514 if ((op
->vt
->type
.t
& VT_BTYPE
) == VT_FLOAT
||
1515 (op
->vt
->type
.t
& VT_BTYPE
) == VT_DOUBLE
) {
1516 store(tcc_freg(op
->reg
), op
->vt
);
1518 store(tcc_ireg(op
->reg
), op
->vt
);
1521 tcc_error("long long not implemented");
1526 /* generate reg restore code for floating point registers */
1527 for(i
= sizeof(reg_saved
)/sizeof(reg_saved
[0]) - 1; i
>= 0; i
--) {
1529 if (regs_allocated
[reg
]) {
1531 if (REG_IS_FLOAT(reg
)){
1532 /* fld reg, offset(sp) */
1533 gen_le32(7 | (3 << 12) |
1534 ENCODE_RD(reg
) | ENCODE_RS1(2) | 0);
1536 /* ld reg, offset(sp) */
1537 gen_le32(3 | (3 << 12) |
1538 ENCODE_RD(reg
) | ENCODE_RS1(2) | 0);
1540 /* addi sp, sp, offset */
1541 gen_le32((4 << 2) | 3 |
1542 ENCODE_RD(2) | ENCODE_RS1(2) | 8 << 20);
1548 /* return the constraint priority (we allocate first the lowest
1549 numbered constraints) */
1550 static inline int constraint_priority(const char *str
)
1552 // TODO: How is this chosen??
1553 int priority
, c
, pr
;
1555 /* we take the lowest priority */
1563 case 'A': // address that is held in a general-purpose register.
1564 case 'S': // constraint that matches an absolute symbolic address.
1565 case 'f': // register [float]
1566 case 'r': // register [general]
1567 case 'p': // valid memory address for load,store [general]
1570 case 'I': // 12 bit signed immedate
1571 case 'i': // immediate integer operand, including symbolic constants [general]
1572 case 'm': // memory operand [general]
1573 case 'g': // general-purpose-register, memory, immediate integer [general]
1577 tcc_error("unimp: vector constraints '%d'", c
);
1581 tcc_error("unknown constraint '%d'", c
);
1590 static const char *skip_constraint_modifiers(const char *p
)
1592 /* Constraint modifier:
1593 = Operand is written to by this instruction
1594 + Operand is both read and written to by this instruction
1595 % Instruction is commutative for this operand and the following operand.
1597 Per-alternative constraint modifier:
1598 & Operand is clobbered before the instruction is done using the input operands
1600 while (*p
== '=' || *p
== '&' || *p
== '+' || *p
== '%')
1605 #define REG_OUT_MASK 0x01
1606 #define REG_IN_MASK 0x02
1608 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1610 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1611 int nb_operands
, int nb_outputs
,
1612 const uint8_t *clobber_regs
,
1615 /* TODO: Simple constraints
1617 o memory operand that is offsetable
1618 V memory but not offsetable
1619 < memory operand with autodecrement addressing is allowed. Restrictions apply.
1620 > memory operand with autoincrement addressing is allowed. Restrictions apply.
1621 n immediate integer operand with a known numeric value
1622 E immediate floating operand (const_double) is allowed, but only if target=host
1623 F immediate floating operand (const_double or const_vector) is allowed
1624 s immediate integer operand whose value is not an explicit integer
1625 X any operand whatsoever
1626 0...9 (postfix); (can also be more than 1 digit number); an operand that matches the specified operand number is allowed
1629 /* TODO: RISCV constraints
1631 K A 5-bit unsigned immediate for CSR access instructions.
1632 A An address that is held in a general-purpose register.
1633 S A constraint that matches an absolute symbolic address.
1634 vr A vector register (if available)..
1635 vd A vector register, excluding v0 (if available).
1636 vm A vector register, only v0 (if available).
1639 int sorted_op
[MAX_ASM_OPERANDS
];
1640 int i
, j
, k
, p1
, p2
, tmp
, reg
, c
, reg_mask
;
1642 uint8_t regs_allocated
[NB_ASM_REGS
];
1645 for (i
= 0; i
< nb_operands
; i
++) {
1647 op
->input_index
= -1;
1653 /* compute constraint priority and evaluate references to output
1654 constraints if input constraints */
1655 for (i
= 0; i
< nb_operands
; i
++) {
1657 str
= op
->constraint
;
1658 str
= skip_constraint_modifiers(str
);
1659 if (isnum(*str
) || *str
== '[') {
1660 /* this is a reference to another constraint */
1661 k
= find_constraint(operands
, nb_operands
, str
, NULL
);
1662 if ((unsigned) k
>= i
|| i
< nb_outputs
)
1663 tcc_error("invalid reference in constraint %d ('%s')",
1666 if (operands
[k
].input_index
>= 0)
1667 tcc_error("cannot reference twice the same operand");
1668 operands
[k
].input_index
= i
;
1670 } else if ((op
->vt
->r
& VT_VALMASK
) == VT_LOCAL
1672 && (reg
= op
->vt
->sym
->r
& VT_VALMASK
) < VT_CONST
) {
1676 op
->priority
= constraint_priority(str
);
1680 /* sort operands according to their priority */
1681 for (i
= 0; i
< nb_operands
; i
++)
1683 for (i
= 0; i
< nb_operands
- 1; i
++) {
1684 for (j
= i
+ 1; j
< nb_operands
; j
++) {
1685 p1
= operands
[sorted_op
[i
]].priority
;
1686 p2
= operands
[sorted_op
[j
]].priority
;
1689 sorted_op
[i
] = sorted_op
[j
];
1695 for (i
= 0; i
< NB_ASM_REGS
; i
++) {
1696 if (clobber_regs
[i
])
1697 regs_allocated
[i
] = REG_IN_MASK
| REG_OUT_MASK
;
1699 regs_allocated
[i
] = 0;
1702 /* allocate registers and generate corresponding asm moves */
1703 for (i
= 0; i
< nb_operands
; i
++) {
1706 str
= op
->constraint
;
1707 /* no need to allocate references */
1708 if (op
->ref_index
>= 0)
1710 /* select if register is used for output, input or both */
1711 if (op
->input_index
>= 0) {
1712 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1713 } else if (j
< nb_outputs
) {
1714 reg_mask
= REG_OUT_MASK
;
1716 reg_mask
= REG_IN_MASK
;
1719 if (is_reg_allocated(op
->reg
))
1721 ("asm regvar requests register that's taken already");
1727 case '=': // Operand is written-to
1729 case '+': // Operand is both READ and written-to
1732 case '&': // Operand is clobbered before the instruction is done using the input operands
1733 if (j
>= nb_outputs
)
1734 tcc_error("'%c' modifier can only be applied to outputs", c
);
1735 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1737 case 'r': // general-purpose register
1738 case 'p': // loadable/storable address
1739 /* any general register */
1741 if ((reg
= op
->reg
) >= 0)
1743 else for (reg
= 10; reg
<= 18; reg
++) {
1744 if (!is_reg_allocated(reg
))
1749 /* now we can reload in the register */
1752 regs_allocated
[reg
] |= reg_mask
;
1754 case 'f': // floating pont register
1755 /* floating point register */
1756 /* From fa0 to fa7 */
1757 if ((reg
= op
->reg
) >= 0)
1759 else for (reg
= 42; reg
<= 50; reg
++) {
1760 if (!is_reg_allocated(reg
))
1764 case 'I': // I-Type 12 bit signed immediate
1765 case 'i': // immediate integer operand, including symbolic constants
1766 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
))
1769 case 'm': // memory operand
1770 case 'g': // any register
1771 /* nothing special to do because the operand is already in
1772 memory, except if the pointer itself is stored in a
1773 memory variable (VT_LLOCAL case) */
1774 /* XXX: fix constant case */
1775 /* if it is a reference to a memory zone, it must lie
1776 in a register, so we reserve the register in the
1777 input registers and a load will be generated
1779 if (j
< nb_outputs
|| c
== 'm') {
1780 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1781 /* any general register: from a0 to a7 */
1782 for (reg
= 10; reg
<= 18; reg
++) {
1783 if (!(regs_allocated
[reg
] & REG_IN_MASK
))
1788 /* now we can reload in the register */
1789 regs_allocated
[reg
] |= REG_IN_MASK
;
1796 tcc_error("asm constraint %d ('%s') could not be satisfied",
1800 /* if a reference is present for that operand, we assign it too */
1801 if (op
->input_index
>= 0) {
1802 operands
[op
->input_index
].reg
= op
->reg
;
1803 operands
[op
->input_index
].is_llong
= op
->is_llong
;
1807 /* compute out_reg. It is used to store outputs registers to memory
1808 locations references by pointers (VT_LLOCAL case) */
1810 for (i
= 0; i
< nb_operands
; i
++) {
1813 (op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&& !op
->is_memory
) {
1814 if (REG_IS_FLOAT(op
->reg
)){
1815 /* From fa0 to fa7 */
1816 for (reg
= 42; reg
<= 50; reg
++) {
1817 if (!(regs_allocated
[reg
] & REG_OUT_MASK
))
1822 for (reg
= 10; reg
<= 18; reg
++) {
1823 if (!(regs_allocated
[reg
] & REG_OUT_MASK
))
1827 tcc_error("could not find free output register for reloading");
1834 /* print sorted constraints */
1836 for (i
= 0; i
< nb_operands
; i
++) {
1839 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1841 op
->id
? get_tok_str(op
->id
, NULL
) : "",
1842 op
->constraint
, op
->vt
->r
, op
->reg
);
1845 printf("out_reg=%d\n", *pout_reg
);
1849 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1854 if (!strcmp(str
, "memory") ||
1855 !strcmp(str
, "cc") ||
1856 !strcmp(str
, "flags"))
1858 ts
= tok_alloc(str
, strlen(str
));
1859 reg
= asm_parse_regvar(ts
->tok
);
1861 tcc_error("invalid clobber register '%s'", str
);
1863 clobber_regs
[reg
] = 1;
1866 ST_FUNC
int asm_parse_regvar (int t
)
1868 /* PC register not implemented */
1869 if (t
>= TOK_ASM_pc
|| t
< TOK_ASM_x0
)
1873 return t
- TOK_ASM_x0
;
1875 if (t
< TOK_ASM_zero
)
1876 return t
- TOK_ASM_f0
+ 32; // Use higher 32 for floating point
1879 if (t
< TOK_ASM_ft0
)
1880 return t
- TOK_ASM_zero
;
1882 return t
- TOK_ASM_ft0
+ 32; // Use higher 32 for floating point
1885 /*************************************************************/
1888 /* caller: Add funct6, funct2 into opcode */
1889 static void asm_emit_ca(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
)
1893 if (rd
->type
!= OP_REG
) {
1894 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1898 if (rs2
->type
!= OP_REG
) {
1899 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1903 /* subtract index of x8 */
1907 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
1909 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1914 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1918 /* CA-type instruction:
1925 gen_le16(opcode
| C_ENCODE_RS2(src
) | C_ENCODE_RS1(dst
));
1928 static void asm_emit_cb(int token
, uint16_t opcode
, const Operand
*rs1
, const Operand
*imm
)
1933 if (rs1
->type
!= OP_REG
) {
1934 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
1938 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1939 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1946 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
1953 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
1957 /* CB-type instruction:
1964 /* non-branch also using CB:
1973 case TOK_ASM_c_beqz
:
1974 case TOK_ASM_c_bnez
:
1975 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));
1978 gen_le16(opcode
| C_ENCODE_RS1(src
) | ((offset
& 0x1f) << 2) | (NTH_BIT(offset
, 5) << 12));
1983 static void asm_emit_ci(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
)
1987 if (rd
->type
!= OP_REG
) {
1988 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
1992 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
1993 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
1997 immediate
= imm
->e
.v
;
1999 /* CI-type instruction:
2007 case TOK_ASM_c_addi
:
2008 case TOK_ASM_c_addiw
:
2010 case TOK_ASM_c_slli
:
2011 gen_le16(opcode
| ((immediate
& 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
2013 case TOK_ASM_c_addi16sp
:
2014 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));
2017 gen_le16(opcode
| (((immediate
>> 12) & 0x1f) << 2) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 17) << 12));
2019 case TOK_ASM_c_fldsp
:
2020 case TOK_ASM_c_ldsp
:
2021 gen_le16(opcode
| (((immediate
>> 6) & 7) << 2) | (((immediate
>> 3) & 2) << 5) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
2023 case TOK_ASM_c_flwsp
:
2024 case TOK_ASM_c_lwsp
:
2025 gen_le16(opcode
| (((immediate
>> 6) & 3) << 2) | (((immediate
>> 2) & 7) << 4) | ENCODE_RD(rd
->reg
) | (NTH_BIT(immediate
, 5) << 12));
2031 expect("known instruction");
2035 /* caller: Add funct3 into opcode */
2036 static void asm_emit_ciw(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*imm
)
2041 if (rd
->type
!= OP_REG
) {
2042 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
2046 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
2047 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
2054 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
2060 if (nzuimm
> 0x3fc) {
2061 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x3ff", get_tok_str(token
, NULL
));
2066 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token
, NULL
));
2070 /* CIW-type instruction:
2076 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));
2079 /* caller: Add funct3 into opcode */
2080 static void asm_emit_cj(int token
, uint16_t opcode
, const Operand
*imm
)
2085 if (imm
->type
!= OP_IM12S
) {
2086 tcc_error("'%s': Expected source operand that is a 12-bit immediate value", get_tok_str(token
, NULL
));
2093 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token
, NULL
));
2097 /* CJ-type instruction:
2099 12...2 offset[11|4|9:8|10|6|7|3:1|5]
2102 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));
2105 /* caller: Add funct3 into opcode */
2106 static void asm_emit_cl(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs1
, const Operand
*imm
)
2111 if (rd
->type
!= OP_REG
) {
2112 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
2116 if (rs1
->type
!= OP_REG
) {
2117 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
2121 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
2122 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
2130 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
2135 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
2141 if (offset
> 0xff) {
2142 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token
, NULL
));
2147 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
2151 /* CL-type instruction:
2163 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));
2168 gen_le16(opcode
| C_ENCODE_RS2(dst
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
2171 expect("known instruction");
2175 /* caller: Add funct4 into opcode */
2176 static void asm_emit_cr(int token
, uint16_t opcode
, const Operand
*rd
, const Operand
*rs2
)
2178 if (rd
->type
!= OP_REG
) {
2179 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
2183 if (rs2
->type
!= OP_REG
) {
2184 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
2188 /* CR-type instruction:
2194 gen_le16(opcode
| C_ENCODE_RS1(rd
->reg
) | C_ENCODE_RS2(rs2
->reg
));
2197 /* caller: Add funct3 into opcode */
2198 static void asm_emit_cs(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*rs1
, const Operand
*imm
)
2203 if (rs2
->type
!= OP_REG
) {
2204 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
2208 if (rs1
->type
!= OP_REG
) {
2209 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token
, NULL
));
2213 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
2214 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
2218 base
= rs1
->reg
- 8;
2222 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token
, NULL
));
2227 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token
, NULL
));
2233 if (offset
> 0xff) {
2234 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token
, NULL
));
2239 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
2243 /* CS-type instruction:
2254 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));
2259 gen_le16(opcode
| C_ENCODE_RS2(base
) | C_ENCODE_RS1(src
) | (((offset
>> 6) & 3) << 5) | (((offset
>> 3) & 7) << 10));
2262 expect("known instruction");
2266 /* caller: Add funct3 into opcode */
2267 static void asm_emit_css(int token
, uint16_t opcode
, const Operand
*rs2
, const Operand
*imm
)
2271 if (rs2
->type
!= OP_REG
) {
2272 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token
, NULL
));
2276 if (imm
->type
!= OP_IM12S
&& imm
->type
!= OP_IM32
) {
2277 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token
, NULL
));
2283 if (offset
> 0xff) {
2284 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token
, NULL
));
2289 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token
, NULL
));
2293 /* CSS-type instruction:
2301 case TOK_ASM_c_fswsp
:
2302 case TOK_ASM_c_swsp
:
2303 gen_le16(opcode
| ENCODE_RS2(rs2
->reg
) | (((offset
>> 6) & 3) << 7) | (((offset
>> 2) & 0xf) << 9));
2306 case TOK_ASM_c_fsdsp
:
2307 case TOK_ASM_c_sdsp
:
2308 gen_le16(opcode
| ENCODE_RS2(rs2
->reg
) | (((offset
>> 6) & 7) << 7) | (((offset
>> 3) & 7) << 10));
2311 expect("known instruction");
2315 /*************************************************************/
2316 #endif /* ndef TARGET_DEFS_ONLY */