Fix Extended Asm ignored constraints
[tinycc.git] / riscv64-asm.c
blob88af663bde4c117801e6457e30150f6aa76f59eb
1 /*************************************************************/
2 /*
3 * RISCV64 assembler for TCC
5 */
7 #ifdef TARGET_DEFS_ONLY
9 #define CONFIG_TCC_ASM
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 /*************************************************************/
18 #else
19 /*************************************************************/
20 #define USING_GLOBALS
21 #include "tcc.h"
23 enum {
24 OPT_REG,
25 OPT_IM12S,
26 OPT_IM32,
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 {
43 uint32_t type;
44 union {
45 uint8_t reg;
46 uint16_t regset;
47 ExprValue e;
49 } 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);
73 /* C extension */
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 ? */
85 ST_FUNC void g(int c)
87 int ind1;
88 if (nocode_wanted)
89 return;
90 ind1 = ind + 1;
91 if (ind1 > cur_text_section->data_allocated)
92 section_realloc(cur_text_section, ind1);
93 cur_text_section->data[ind] = c;
94 ind = ind1;
97 ST_FUNC void gen_le16 (int i)
99 g(i);
100 g(i>>8);
103 ST_FUNC void gen_le32 (int i)
105 int ind1;
106 if (nocode_wanted)
107 return;
108 ind1 = ind + 4;
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)
119 gen_le32(pe->v);
122 static void asm_emit_opcode(uint32_t opcode) {
123 gen_le32(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};
131 switch (token) {
132 // Sync instructions
134 case TOK_ASM_fence: // I
135 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
136 return;
137 case TOK_ASM_fence_i: // I
138 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
139 return;
141 // System calls
143 case TOK_ASM_ecall: // I (pseudo)
144 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
145 return;
146 case TOK_ASM_ebreak: // I (pseudo)
147 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
148 return;
150 // Other
152 case TOK_ASM_nop:
153 asm_emit_i(token, (4 << 2) | 3, &nil, &nil, &zimm);
154 return;
156 case TOK_ASM_wfi:
157 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
158 return;
160 /* Pseudoinstructions */
161 case TOK_ASM_ret:
162 /* jalr zero, x1, 0 */
163 asm_emit_opcode( 0x67 | (0 << 12) | ENCODE_RS1(1) );
164 return;
166 /* C extension */
167 case TOK_ASM_c_ebreak:
168 asm_emit_cr(token, 2 | (9 << 12), &nil, &nil);
169 return;
170 case TOK_ASM_c_nop:
171 asm_emit_ci(token, 1, &nil, &zimm);
172 return;
174 default:
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)
182 ExprValue e = {0};
183 Sym label = {0};
184 int8_t reg;
186 op->type = 0;
188 if ((reg = asm_parse_regvar(tok)) != -1) {
189 next(); // skip register name
190 op->type = OP_REG;
191 op->reg = (uint8_t) reg;
192 return;
193 } else if (tok == '$') {
194 /* constant value */
195 next(); // skip '#' or '$'
196 } else if ((e.v = asm_parse_csrvar(tok)) != -1) {
197 next();
198 } else {
199 asm_expr(s1, &e);
201 op->type = OP_IM32;
202 op->e = e;
203 /* compare against unsigned 12-bit maximum */
204 if (!op->e.sym) {
205 if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000)
206 op->type = OP_IM12S;
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);
213 else
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);
218 op->type = OP_IM12S;
219 op->e.v = 0;
220 } else {
221 expect("operand");
225 static void parse_operands(TCCState *s1, Operand* ops, int count){
226 int i;
227 for (i = 0; i < count; i++) {
228 if ( i != 0 ) {
229 if ( tok == ',')
230 next();
231 else
232 expect("','");
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};
242 Operand op;
244 parse_operand(s1, &ops[0]);
245 if ( tok == ',')
246 next();
247 else
248 expect("','");
250 if ( tok == '(') {
251 /* `X, (Y)` case*/
252 next();
253 parse_operand(s1, &ops[1]);
254 if ( tok == ')') next(); else expect("')'");
255 ops[2] = zimm;
256 } else {
257 parse_operand(s1, &ops[2]);
258 if ( tok == '('){
259 /* `X, imm(Y)` case*/
260 next();
261 parse_operand(s1, &ops[1]);
262 if ( tok == ')') next(); else expect("')'");
263 } else {
264 /* `X, Y` case*/
265 /* we parsed Y thinking it was imm, swap and default imm to zero */
266 op = ops[2];
267 ops[1] = ops[2];
268 ops[2] = op;
269 ops[2] = zimm;
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};
277 Operand ops[2];
278 parse_operand(s1, &ops[0]);
279 if ( ops[0].type != OP_REG ) {
280 /* no more operands, it's the pseudoinstruction:
281 * jal offset
282 * Expand to:
283 * jal ra, offset
285 ops[1] = ops[0];
286 ops[0] = ra;
287 goto emit;
289 if ( tok == ',')
290 next();
291 else
292 expect("','");
293 parse_operand(s1, &ops[1]);
294 emit:
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};
305 Operand ops[3];
306 Operand op;
308 parse_operand(s1, &ops[0]);
309 if ( tok == ',')
310 next();
311 else {
312 /* no more operands, it's the pseudoinstruction:
313 * jalr rs
314 * Expand to:
315 * jalr ra, 0(rs)
317 asm_emit_i(token, 0x67 | (0 << 12), &ra, &ops[0], &zimm);
318 return;
321 if ( tok == '(') {
322 /* `X, (Y)` case*/
323 next();
324 parse_operand(s1, &ops[1]);
325 if ( tok == ')') next(); else expect("')'");
326 ops[2] = zimm;
327 } else {
328 parse_operand(s1, &ops[2]);
329 if ( tok == '('){
330 /* `X, imm(Y)` case*/
331 next();
332 parse_operand(s1, &ops[1]);
333 if ( tok == ')') next(); else expect("')'");
334 } else {
335 /* `X, Y` case*/
336 /* we parsed Y thinking it was imm, swap and default imm to zero */
337 op = ops[2];
338 ops[1] = ops[2];
339 ops[2] = op;
340 ops[2] = zimm;
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);
351 Operand op;
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);
359 switch (token) {
360 /* pseudoinstructions */
361 case TOK_ASM_rdcycle:
362 asm_emit_opcode(opcode | (0xC00 << 20));
363 return;
364 case TOK_ASM_rdcycleh:
365 asm_emit_opcode(opcode | (0xC80 << 20));
366 return;
367 case TOK_ASM_rdtime:
368 asm_emit_opcode(opcode | (0xC01 << 20) | ENCODE_RD(op.reg));
369 return;
370 case TOK_ASM_rdtimeh:
371 asm_emit_opcode(opcode | (0xC81 << 20) | ENCODE_RD(op.reg));
372 return;
373 case TOK_ASM_rdinstret:
374 asm_emit_opcode(opcode | (0xC02 << 20) | ENCODE_RD(op.reg));
375 return;
376 case TOK_ASM_rdinstreth:
377 asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
378 return;
380 case TOK_ASM_jr:
381 /* jalr zero, 0(rs)*/
382 asm_emit_i(token, 0x67 | (0 << 12), &zero, &op, &zimm);
383 return;
384 case TOK_ASM_call:
385 /* auipc ra, 0 */
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));
390 return;
391 case TOK_ASM_tail:
392 /* auipc x6, 0 */
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));
397 return;
399 /* C extension */
400 case TOK_ASM_c_j:
401 asm_emit_cj(token, 1 | (5 << 13), &op);
402 return;
403 case TOK_ASM_c_jal: /* RV32C-only */
404 asm_emit_cj(token, 1 | (1 << 13), &op);
405 return;
406 case TOK_ASM_c_jalr:
407 asm_emit_cr(token, 2 | (9 << 12), &op, &zero);
408 return;
409 case TOK_ASM_c_jr:
410 asm_emit_cr(token, 2 | (8 << 12), &op, &zero);
411 return;
412 default:
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));
421 return;
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));
425 return;
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));
428 return;
430 /* U-type instruction:
431 31...12 imm[31:12]
432 11...7 rd
433 6...0 opcode */
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}};
441 Operand ops[2];
442 int32_t lo;
443 uint32_t hi;
445 parse_operands(s1, &ops[0], 2);
446 switch (token) {
447 case TOK_ASM_lui:
448 asm_emit_u(token, (0xD << 2) | 3, &ops[0], &ops[1]);
449 return;
450 case TOK_ASM_auipc:
451 asm_emit_u(token, (0x05 << 2) | 3, &ops[0], &ops[1]);
452 return;
454 /* C extension */
455 case TOK_ASM_c_add:
456 asm_emit_cr(token, 2 | (9 << 12), ops, ops + 1);
457 return;
458 case TOK_ASM_c_mv:
459 asm_emit_cr(token, 2 | (8 << 12), ops, ops + 1);
460 return;
462 case TOK_ASM_c_addi16sp:
463 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
464 return;
465 case TOK_ASM_c_addi:
466 asm_emit_ci(token, 1, ops, ops + 1);
467 return;
468 case TOK_ASM_c_addiw:
469 asm_emit_ci(token, 1 | (1 << 13), ops, ops + 1);
470 return;
471 case TOK_ASM_c_fldsp:
472 asm_emit_ci(token, 2 | (1 << 13), ops, ops + 1);
473 return;
474 case TOK_ASM_c_flwsp: /* RV32FC-only */
475 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
476 return;
477 case TOK_ASM_c_ldsp:
478 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
479 return;
480 case TOK_ASM_c_li:
481 asm_emit_ci(token, 1 | (2 << 13), ops, ops + 1);
482 return;
483 case TOK_ASM_c_lui:
484 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
485 return;
486 case TOK_ASM_c_lwsp:
487 asm_emit_ci(token, 2 | (2 << 13), ops, ops + 1);
488 return;
489 case TOK_ASM_c_slli:
490 asm_emit_ci(token, 2, ops, ops + 1);
491 return;
493 case TOK_ASM_c_addi4spn:
494 asm_emit_ciw(token, 0, ops, ops + 1);
495 return;
497 #define CA (1 | (3 << 10) | (4 << 13))
498 case TOK_ASM_c_addw:
499 asm_emit_ca(token, CA | (1 << 5) | (1 << 12), ops, ops + 1);
500 return;
501 case TOK_ASM_c_and:
502 asm_emit_ca(token, CA | (3 << 5), ops, ops + 1);
503 return;
504 case TOK_ASM_c_or:
505 asm_emit_ca(token, CA | (2 << 5), ops, ops + 1);
506 return;
507 case TOK_ASM_c_sub:
508 asm_emit_ca(token, CA, ops, ops + 1);
509 return;
510 case TOK_ASM_c_subw:
511 asm_emit_ca(token, CA | (1 << 12), ops, ops + 1);
512 return;
513 case TOK_ASM_c_xor:
514 asm_emit_ca(token, CA | (1 << 5), ops, ops + 1);
515 return;
516 #undef CA
518 case TOK_ASM_c_andi:
519 asm_emit_cb(token, 1 | (2 << 10) | (4 << 13), ops, ops + 1);
520 return;
521 case TOK_ASM_c_beqz:
522 asm_emit_cb(token, 1 | (6 << 13), ops, ops + 1);
523 return;
524 case TOK_ASM_c_bnez:
525 asm_emit_cb(token, 1 | (7 << 13), ops, ops + 1);
526 return;
527 case TOK_ASM_c_srai:
528 asm_emit_cb(token, 1 | (1 << 10) | (4 << 13), ops, ops + 1);
529 return;
530 case TOK_ASM_c_srli:
531 asm_emit_cb(token, 1 | (4 << 13), ops, ops + 1);
532 return;
534 case TOK_ASM_c_sdsp:
535 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
536 return;
537 case TOK_ASM_c_swsp:
538 asm_emit_css(token, 2 | (6 << 13), ops, ops + 1);
539 return;
540 case TOK_ASM_c_fswsp: /* RV32FC-only */
541 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
542 return;
543 case TOK_ASM_c_fsdsp:
544 asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
545 return;
547 /* pseudoinstructions */
548 /* rd, sym */
549 case TOK_ASM_la:
550 /* auipc rd, 0 */
551 asm_emit_u(token, 3 | (5 << 2), ops, ops + 1);
552 /* lw rd, rd, 0 */
553 asm_emit_i(token, 3 | (2 << 12), ops, ops, ops + 1);
554 return;
555 case TOK_ASM_lla:
556 /* auipc rd, 0 */
557 asm_emit_u(token, 3 | (5 << 2), ops, ops + 1);
558 /* addi rd, rd, 0 */
559 asm_emit_i(token, 3 | (4 << 2), ops, ops, ops + 1);
560 return;
561 case TOK_ASM_li:
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));
565 lo = ops[1].e.v;
566 hi = (int64_t)ops[1].e.v >> 32;
567 if(lo < 0){
568 hi += 1;
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 */
577 imm.e.v = 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 */
583 imm.e.v = 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)) */
586 lo = lo << 12 >> 12;
587 imm.e.v = lo >> 8;
588 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm);
589 /* slli rd, rd, 8 */
590 imm.e.v = 8;
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)) */
593 lo &= 0xff;
594 imm.e.v = lo << 20 >> 20;
595 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[0], &imm);
596 return;
597 case TOK_ASM_mv:
598 /* addi rd, rs, 0 */
599 asm_emit_i(token, 3 | (4 << 2), &ops[0], &ops[1], &imm);
600 return;
601 case TOK_ASM_not:
602 /* xori rd, rs, -1 */
603 imm.e.v = -1;
604 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &imm);
605 return;
606 case TOK_ASM_neg:
607 /* sub rd, x0, rs */
608 imm.e.v = 1;
609 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
610 return;
611 case TOK_ASM_negw:
612 /* sub rd, x0, rs */
613 imm.e.v = 1;
614 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
615 return;
616 case TOK_ASM_jump:
617 /* auipc x5, 0 */
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));
622 return;
623 case TOK_ASM_seqz:
624 /* sltiu rd, rs, 1 */
625 imm.e.v = 1;
626 asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &imm);
627 return;
628 case TOK_ASM_snez:
629 /* sltu rd, zero, rs */
630 imm.e.v = 1;
631 asm_emit_r(token, (0xC << 2) | 3 | (3 << 12), &ops[0], &zero, &ops[1]);
632 return;
633 case TOK_ASM_sltz:
634 /* slt rd, rs, zero */
635 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &ops[1], &zero);
636 return;
637 case TOK_ASM_sgtz:
638 /* slt rd, zero, rs */
639 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]);
640 return;
641 case TOK_ASM_bnez:
642 /* bne rs, zero, offset */
643 asm_emit_b(token, 0x63 | (1 << 12), &ops[0], &zero, &ops[1]);
644 return;
645 case TOK_ASM_beqz:
646 /* bne rs, zero, offset */
647 asm_emit_b(token, 0x63 | (0 << 12), &ops[0], &zero, &ops[1]);
648 return;
649 case TOK_ASM_blez:
650 /* bge rs, zero, offset */
651 asm_emit_b(token, 0x63 | (5 << 12), &ops[0], &zero, &ops[1]);
652 return;
653 case TOK_ASM_bgez:
654 /* bge zero, rs, offset */
655 asm_emit_b(token, 0x63 | (5 << 12), &zero, &ops[0], &ops[1]);
656 return;
657 case TOK_ASM_bltz:
658 /* blt rs, zero, offset */
659 asm_emit_b(token, 0x63 | (4 << 12), &ops[0], &zero, &ops[1]);
660 return;
661 case TOK_ASM_bgtz:
662 /* blt zero, rs, offset */
663 asm_emit_b(token, 0x63 | (4 << 12), &zero, &ops[0], &ops[1]);
664 return;
666 default:
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));
676 return;
678 if (rs1->type != OP_REG) {
679 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
680 return;
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));
684 return;
686 /* R-type instruction:
687 31...25 funct7
688 24...20 rs2
689 19...15 rs1
690 14...12 funct3
691 11...7 rd
692 6...0 opcode */
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));
701 return;
703 if (rs1->type != OP_REG) {
704 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
705 return;
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));
709 return;
711 /* I-type instruction:
712 31...20 imm[11:0]
713 19...15 rs1
714 14...12 funct3
715 11...7 rd
716 6...0 opcode */
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)
723 uint32_t imm;
725 if (rd->type != OP_REG) {
726 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
727 return;
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));
731 return;
734 imm = rs2->e.v;
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));
739 return;
742 if (imm & 1) {
743 tcc_error("'%s': Expected second source operand that is an even immediate value", get_tok_str(token, NULL));
744 return;
746 /* J-type instruction:
747 31 imm[20]
748 30...21 imm[10:1]
749 20 imm[11]
750 19...12 imm[19:12]
751 11...7 rd
752 6...0 opcode */
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)
759 Operand ops[3];
760 parse_mem_access_operands(s1, &ops[0]);
762 /* Pseudoinstruction: inst reg, label
763 * expand to:
764 * auipc reg, 0
765 * inst reg, 0(reg)
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){
769 ops[1] = ops[0];
770 /* set the offset to zero */
771 ops[2].type = OP_IM12S;
772 ops[2].e.v = 0;
773 /* auipc reg, 0 */
774 asm_emit_u(token, (0x05 << 2) | 3, &ops[0], &ops[2]);
777 switch (token) {
778 // l{b|h|w|d}[u] rd, imm(rs1); I-format
779 case TOK_ASM_lb:
780 asm_emit_i(token, (0x0 << 2) | 3, &ops[0], &ops[1], &ops[2]);
781 return;
782 case TOK_ASM_lh:
783 asm_emit_i(token, (0x0 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
784 return;
785 case TOK_ASM_lw:
786 asm_emit_i(token, (0x0 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
787 return;
788 case TOK_ASM_ld:
789 asm_emit_i(token, (0x0 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
790 return;
791 case TOK_ASM_lbu:
792 asm_emit_i(token, (0x0 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
793 return;
794 case TOK_ASM_lhu:
795 asm_emit_i(token, (0x0 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
796 return;
797 case TOK_ASM_lwu:
798 asm_emit_i(token, (0x0 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
799 return;
801 // s{b|h|w|d} rs2, imm(rs1); S-format (with rsX swapped)
802 case TOK_ASM_sb:
803 asm_emit_s(token, (0x8 << 2) | 3 | (0 << 12), &ops[1], &ops[0], &ops[2]);
804 return;
805 case TOK_ASM_sh:
806 asm_emit_s(token, (0x8 << 2) | 3 | (1 << 12), &ops[1], &ops[0], &ops[2]);
807 return;
808 case TOK_ASM_sw:
809 asm_emit_s(token, (0x8 << 2) | 3 | (2 << 12), &ops[1], &ops[0], &ops[2]);
810 return;
811 case TOK_ASM_sd:
812 asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[1], &ops[0], &ops[2]);
813 return;
817 static void asm_ternary_opcode(TCCState *s1, int token)
819 Operand ops[3];
820 parse_operands(s1, &ops[0], 3);
822 switch (token) {
823 case TOK_ASM_sll:
824 asm_emit_r(token, (0xC << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
825 return;
826 case TOK_ASM_slli:
827 asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
828 return;
829 case TOK_ASM_srl:
830 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
831 return;
832 case TOK_ASM_srli:
833 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
834 return;
835 case TOK_ASM_sra:
836 asm_emit_r(token, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
837 return;
838 case TOK_ASM_srai:
839 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops[0], &ops[1], &ops[2]);
840 return;
841 case TOK_ASM_sllw:
842 asm_emit_r(token, (0xE << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
843 return;
844 case TOK_ASM_slliw:
845 asm_emit_i(token, (6 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
846 return;
847 case TOK_ASM_srlw:
848 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
849 return;
850 case TOK_ASM_srliw:
851 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
852 return;
853 case TOK_ASM_sraw:
854 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
855 return;
856 case TOK_ASM_sraiw:
857 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
858 return;
860 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
862 case TOK_ASM_add:
863 asm_emit_r(token, (0xC << 2) | 3, &ops[0], &ops[1], &ops[2]);
864 return;
865 case TOK_ASM_addi:
866 asm_emit_i(token, (4 << 2) | 3, &ops[0], &ops[1], &ops[2]);
867 return;
868 case TOK_ASM_sub:
869 asm_emit_r(token, (0xC << 2) | 3 | (32 << 25), &ops[0], &ops[1], &ops[2]);
870 return;
871 case TOK_ASM_addw:
872 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
873 return;
874 case TOK_ASM_addiw: // 64 bit
875 asm_emit_i(token, (0x6 << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
876 return;
877 case TOK_ASM_subw:
878 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
879 return;
881 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
883 case TOK_ASM_xor:
884 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
885 return;
886 case TOK_ASM_xori:
887 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
888 return;
889 case TOK_ASM_or:
890 asm_emit_r(token, (0xC << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
891 return;
892 case TOK_ASM_ori:
893 asm_emit_i(token, (0x4 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
894 return;
895 case TOK_ASM_and:
896 asm_emit_r(token, (0xC << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
897 return;
898 case TOK_ASM_andi:
899 asm_emit_i(token, (0x4 << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
900 return;
902 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
904 case TOK_ASM_slt:
905 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
906 return;
907 case TOK_ASM_slti:
908 asm_emit_i(token, (0x4 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
909 return;
910 case TOK_ASM_sltu:
911 asm_emit_r(token, (0xC << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
912 return;
913 case TOK_ASM_sltiu:
914 asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
915 return;
917 /* branch (RS1, RS2, IMM); B-format */
918 case TOK_ASM_beq:
919 asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2);
920 return;
921 case TOK_ASM_bne:
922 asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2);
923 return;
924 case TOK_ASM_blt:
925 asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2);
926 return;
927 case TOK_ASM_bge:
928 asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2);
929 return;
930 case TOK_ASM_bltu:
931 asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2);
932 return;
933 case TOK_ASM_bgeu:
934 asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2);
935 return;
936 /* related pseudoinstructions */
937 case TOK_ASM_bgt:
938 asm_emit_b(token, 0x63 | (4 << 12), ops + 1, ops, ops + 2);
939 return;
940 case TOK_ASM_ble:
941 asm_emit_b(token, 0x63 | (5 << 12), ops + 1, ops, ops + 2);
942 return;
943 case TOK_ASM_bgtu:
944 asm_emit_b(token, 0x63 | (6 << 12), ops + 1, ops, ops + 2);
945 return;
946 case TOK_ASM_bleu:
947 asm_emit_b(token, 0x63 | (7 << 12), ops + 1, ops, ops + 2);
948 return;
950 /* M extension */
951 case TOK_ASM_div:
952 asm_emit_r(token, 0x33 | (4 << 12) | (1 << 25), ops, ops + 1, ops + 2);
953 return;
954 case TOK_ASM_divu:
955 asm_emit_r(token, 0x33 | (5 << 12) | (1 << 25), ops, ops + 1, ops + 2);
956 return;
957 case TOK_ASM_divuw:
958 asm_emit_r(token, 0x3b | (5 << 12) | (1 << 25), ops, ops + 1, ops + 2);
959 return;
960 case TOK_ASM_divw:
961 asm_emit_r(token, 0x3b | (4 << 12) | (1 << 25), ops, ops + 1, ops + 2);
962 return;
963 case TOK_ASM_mul:
964 asm_emit_r(token, 0x33 | (1 << 25), ops, ops + 1, ops + 2);
965 return;
966 case TOK_ASM_mulh:
967 asm_emit_r(token, 0x33 | (1 << 12) | (1 << 25), ops, ops + 1, ops + 2);
968 return;
969 case TOK_ASM_mulhsu:
970 asm_emit_r(token, 0x33 | (2 << 12) | (1 << 25), ops, ops + 1, ops + 2);
971 return;
972 case TOK_ASM_mulhu:
973 asm_emit_r(token, 0x33 | (3 << 12) | (1 << 25), ops, ops + 1, ops + 2);
974 return;
975 case TOK_ASM_mulw:
976 asm_emit_r(token, 0x3b | (1 << 25), ops, ops + 1, ops + 2);
977 return;
978 case TOK_ASM_rem:
979 asm_emit_r(token, 0x33 | (6 << 12) | (1 << 25), ops, ops + 1, ops + 2);
980 return;
981 case TOK_ASM_remu:
982 asm_emit_r(token, 0x33 | (7 << 12) | (1 << 25), ops, ops + 1, ops + 2);
983 return;
984 case TOK_ASM_remuw:
985 asm_emit_r(token, 0x3b | (7 << 12) | (1 << 25), ops, ops + 1, ops + 2);
986 return;
987 case TOK_ASM_remw:
988 asm_emit_r(token, 0x3b | (6 << 12) | (1 << 25), ops, ops + 1, ops + 2);
989 return;
991 /* Zicsr extension; (rd, csr, rs/uimm) */
992 case TOK_ASM_csrrc:
993 asm_emit_i(token, 0x73 | (3 << 12), ops, ops + 2, ops + 1);
994 return;
995 case TOK_ASM_csrrci:
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);
999 return;
1000 case TOK_ASM_csrrs:
1001 asm_emit_i(token, 0x73 | (2 << 12), ops, ops + 2, ops + 1);
1002 return;
1003 case TOK_ASM_csrrsi:
1004 ops[2].type = OP_REG;
1005 asm_emit_i(token, 0x73 | (6 << 12), ops, ops + 2, ops + 1);
1006 return;
1007 case TOK_ASM_csrrw:
1008 asm_emit_i(token, 0x73 | (1 << 12), ops, ops + 2, ops + 1);
1009 return;
1010 case TOK_ASM_csrrwi:
1011 ops[2].type = OP_REG;
1012 asm_emit_i(token, 0x73 | (5 << 12), ops, ops + 2, ops + 1);
1013 return;
1015 /* C extension */
1016 /* register-based loads and stores (RD, RS1, IMM); CL-format */
1017 case TOK_ASM_c_fld:
1018 asm_emit_cl(token, 1 << 13, ops, ops + 1, ops + 2);
1019 return;
1020 case TOK_ASM_c_flw: /* RV32FC-only */
1021 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
1022 return;
1023 case TOK_ASM_c_fsd:
1024 asm_emit_cs(token, 5 << 13, ops, ops + 1, ops + 2);
1025 return;
1026 case TOK_ASM_c_fsw: /* RV32FC-only */
1027 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
1028 return;
1029 case TOK_ASM_c_ld:
1030 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
1031 return;
1032 case TOK_ASM_c_lw:
1033 asm_emit_cl(token, 2 << 13, ops, ops + 1, ops + 2);
1034 return;
1035 case TOK_ASM_c_sd:
1036 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
1037 return;
1038 case TOK_ASM_c_sw:
1039 asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
1040 return;
1042 default:
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));
1052 return;
1054 if (rs2->type != OP_REG) {
1055 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
1056 return;
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));
1060 return;
1063 uint16_t v = imm->e.v;
1064 /* S-type instruction:
1065 31...25 imm[11:5]
1066 24...20 rs2
1067 19...15 rs1
1068 14...12 funct3
1069 11...7 imm[4:0]
1070 6...0 opcode
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)
1078 uint32_t offset;
1080 if (rs1->type != OP_REG) {
1081 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
1082 return;
1084 if (rs2->type != OP_REG) {
1085 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1086 return;
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));
1090 return;
1093 offset = imm->e.v;
1095 /* B-type instruction:
1096 31 imm[12]
1097 30...25 imm[10:5]
1098 24...20 rs2
1099 19...15 rs1
1100 14...12 funct3
1101 8...11 imm[4:1]
1102 7 imm[11]
1103 6...0 opcode */
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)
1109 switch (token) {
1110 case TOK_ASM_ebreak:
1111 case TOK_ASM_ecall:
1112 case TOK_ASM_fence:
1113 case TOK_ASM_fence_i:
1114 case TOK_ASM_hrts:
1115 case TOK_ASM_mrth:
1116 case TOK_ASM_mrts:
1117 case TOK_ASM_wfi:
1118 asm_nullary_opcode(s1, token);
1119 return;
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);
1128 return;
1130 case TOK_ASM_lui:
1131 case TOK_ASM_auipc:
1132 asm_binary_opcode(s1, token);
1133 return;
1135 case TOK_ASM_lb:
1136 case TOK_ASM_lh:
1137 case TOK_ASM_lw:
1138 case TOK_ASM_ld:
1139 case TOK_ASM_lbu:
1140 case TOK_ASM_lhu:
1141 case TOK_ASM_lwu:
1142 case TOK_ASM_sb:
1143 case TOK_ASM_sh:
1144 case TOK_ASM_sw:
1145 case TOK_ASM_sd:
1146 asm_mem_access_opcode(s1, token);
1147 break;
1149 case TOK_ASM_jalr:
1150 asm_jalr_opcode(s1, token); /* it can be a pseudo instruction too*/
1151 break;
1152 case TOK_ASM_jal:
1153 asm_jal_opcode(s1, token); /* it can be a pseudo instruction too*/
1154 break;
1156 case TOK_ASM_add:
1157 case TOK_ASM_addi:
1158 case TOK_ASM_addiw:
1159 case TOK_ASM_addw:
1160 case TOK_ASM_and:
1161 case TOK_ASM_andi:
1162 case TOK_ASM_beq:
1163 case TOK_ASM_bge:
1164 case TOK_ASM_bgeu:
1165 case TOK_ASM_blt:
1166 case TOK_ASM_bltu:
1167 case TOK_ASM_bne:
1168 case TOK_ASM_or:
1169 case TOK_ASM_ori:
1170 case TOK_ASM_sll:
1171 case TOK_ASM_slli:
1172 case TOK_ASM_slliw:
1173 case TOK_ASM_sllw:
1174 case TOK_ASM_slt:
1175 case TOK_ASM_slti:
1176 case TOK_ASM_sltiu:
1177 case TOK_ASM_sltu:
1178 case TOK_ASM_sra:
1179 case TOK_ASM_srai:
1180 case TOK_ASM_sraiw:
1181 case TOK_ASM_sraw:
1182 case TOK_ASM_srl:
1183 case TOK_ASM_srli:
1184 case TOK_ASM_srliw:
1185 case TOK_ASM_srlw:
1186 case TOK_ASM_sub:
1187 case TOK_ASM_subw:
1188 case TOK_ASM_xor:
1189 case TOK_ASM_xori:
1190 /* M extension */
1191 case TOK_ASM_div:
1192 case TOK_ASM_divu:
1193 case TOK_ASM_divuw:
1194 case TOK_ASM_divw:
1195 case TOK_ASM_mul:
1196 case TOK_ASM_mulh:
1197 case TOK_ASM_mulhsu:
1198 case TOK_ASM_mulhu:
1199 case TOK_ASM_mulw:
1200 case TOK_ASM_rem:
1201 case TOK_ASM_remu:
1202 case TOK_ASM_remuw:
1203 case TOK_ASM_remw:
1204 /* Zicsr extension */
1205 case TOK_ASM_csrrc:
1206 case TOK_ASM_csrrci:
1207 case TOK_ASM_csrrs:
1208 case TOK_ASM_csrrsi:
1209 case TOK_ASM_csrrw:
1210 case TOK_ASM_csrrwi:
1211 asm_ternary_opcode(s1, token);
1212 return;
1214 /* C extension */
1215 case TOK_ASM_c_ebreak:
1216 case TOK_ASM_c_nop:
1217 asm_nullary_opcode(s1, token);
1218 return;
1220 case TOK_ASM_c_j:
1221 case TOK_ASM_c_jal:
1222 case TOK_ASM_c_jalr:
1223 case TOK_ASM_c_jr:
1224 asm_unary_opcode(s1, token);
1225 return;
1227 case TOK_ASM_c_add:
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:
1233 case TOK_ASM_c_and:
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:
1242 case TOK_ASM_c_li:
1243 case TOK_ASM_c_lui:
1244 case TOK_ASM_c_lwsp:
1245 case TOK_ASM_c_mv:
1246 case TOK_ASM_c_or:
1247 case TOK_ASM_c_sdsp:
1248 case TOK_ASM_c_slli:
1249 case TOK_ASM_c_srai:
1250 case TOK_ASM_c_srli:
1251 case TOK_ASM_c_sub:
1252 case TOK_ASM_c_subw:
1253 case TOK_ASM_c_swsp:
1254 case TOK_ASM_c_xor:
1255 asm_binary_opcode(s1, token);
1256 return;
1258 case TOK_ASM_c_fld:
1259 case TOK_ASM_c_flw:
1260 case TOK_ASM_c_fsd:
1261 case TOK_ASM_c_fsw:
1262 case TOK_ASM_c_ld:
1263 case TOK_ASM_c_lw:
1264 case TOK_ASM_c_sd:
1265 case TOK_ASM_c_sw:
1266 asm_ternary_opcode(s1, token);
1267 return;
1269 /* pseudoinstructions */
1270 case TOK_ASM_nop:
1271 case TOK_ASM_ret:
1272 asm_nullary_opcode(s1, token);
1273 return;
1275 case TOK_ASM_jr:
1276 case TOK_ASM_call:
1277 case TOK_ASM_tail:
1278 asm_unary_opcode(s1, token);
1279 return;
1281 case TOK_ASM_la:
1282 case TOK_ASM_lla:
1283 case TOK_ASM_li:
1284 case TOK_ASM_jump:
1285 case TOK_ASM_seqz:
1286 case TOK_ASM_snez:
1287 case TOK_ASM_sltz:
1288 case TOK_ASM_sgtz:
1289 case TOK_ASM_bnez:
1290 case TOK_ASM_beqz:
1291 case TOK_ASM_blez:
1292 case TOK_ASM_bgez:
1293 case TOK_ASM_bltz:
1294 case TOK_ASM_bgtz:
1295 case TOK_ASM_mv:
1296 case TOK_ASM_not:
1297 case TOK_ASM_neg:
1298 case TOK_ASM_negw:
1299 asm_binary_opcode(s1, token);
1300 return;
1302 case TOK_ASM_bgt:
1303 case TOK_ASM_bgtu:
1304 case TOK_ASM_ble:
1305 case TOK_ASM_bleu:
1306 asm_ternary_opcode(s1, token);
1307 return;
1309 default:
1310 expect("known instruction");
1314 static int asm_parse_csrvar(int t)
1316 switch (t) {
1317 case TOK_ASM_cycle:
1318 return 0xc00;
1319 case TOK_ASM_fcsr:
1320 return 3;
1321 case TOK_ASM_fflags:
1322 return 1;
1323 case TOK_ASM_frm:
1324 return 2;
1325 case TOK_ASM_instret:
1326 return 0xc02;
1327 case TOK_ASM_time:
1328 return 0xc01;
1329 case TOK_ASM_cycleh:
1330 return 0xc80;
1331 case TOK_ASM_instreth:
1332 return 0xc82;
1333 case TOK_ASM_timeh:
1334 return 0xc81;
1335 default:
1336 return -1;
1340 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
1342 int r, reg, val;
1343 char buf[64];
1345 r = sv->r;
1346 if ((r & VT_VALMASK) == VT_CONST) {
1347 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' &&
1348 modifier != 'P') {
1349 //cstr_ccat(add_str, '#');
1351 if (r & VT_SYM) {
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)
1365 goto no_offset;
1366 cstr_ccat(add_str, '+');
1368 val = sv->c.i;
1369 if (modifier == 'n')
1370 val = -val;
1371 if (modifier == 'z' && sv->c.i == 0) {
1372 cstr_cat(add_str, "zero", -1);
1373 } else {
1374 snprintf(buf, sizeof(buf), "%d", (int) sv->c.i);
1375 cstr_cat(add_str, buf, -1);
1377 no_offset:;
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;
1389 } else {
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);
1395 } else {
1396 /* register case */
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;
1404 } else {
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,
1426 int out_reg)
1428 uint8_t regs_allocated[NB_ASM_REGS];
1429 ASMOperand *op;
1430 int i, reg;
1432 static const uint8_t reg_saved[] = {
1433 // General purpose regs
1434 8, 9, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
1435 // Float regs
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++) {
1442 op = &operands[i];
1443 if (op->reg >= 0) {
1444 regs_allocated[op->reg] = 1;
1448 if(!is_output) {
1449 /* generate reg save code */
1450 for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) {
1451 reg = reg_saved[i];
1452 if (regs_allocated[reg]) {
1453 /* push */
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) );
1461 } else {
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++) {
1471 op = &operands[i];
1472 if (op->reg >= 0) {
1473 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
1474 op->is_memory) {
1475 /* memory reference case (for both input and
1476 output cases) */
1477 SValue sv;
1478 sv = *op->vt;
1479 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
1480 sv.type.t = VT_PTR;
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);
1487 } else {
1488 load(tcc_ireg(op->reg), op->vt);
1490 if (op->is_llong) {
1491 tcc_error("long long not implemented");
1496 } else {
1497 /* generate save code */
1498 for(i = 0 ; i < nb_outputs; i++) {
1499 op = &operands[i];
1500 if (op->reg >= 0) {
1501 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1502 if (!op->is_memory) {
1503 SValue sv;
1504 sv = *op->vt;
1505 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
1506 sv.type.t = VT_PTR;
1507 load(tcc_ireg(out_reg), &sv);
1509 sv = *op->vt;
1510 sv.r = (sv.r & ~VT_VALMASK) | out_reg;
1511 store(tcc_ireg(op->reg), &sv);
1513 } else {
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);
1517 } else {
1518 store(tcc_ireg(op->reg), op->vt);
1520 if (op->is_llong) {
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--) {
1528 reg = reg_saved[i];
1529 if (regs_allocated[reg]) {
1530 /* pop */
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);
1535 } else {
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 */
1556 priority = 0;
1557 for(;;) {
1558 c = *str;
1559 if (c == '\0')
1560 break;
1561 str++;
1562 switch(c) {
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]
1568 pr = 3;
1569 break;
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]
1574 pr = 4;
1575 break;
1576 case 'v':
1577 tcc_error("unimp: vector constraints '%d'", c);
1578 pr = 0;
1579 break;
1580 default:
1581 tcc_error("unknown constraint '%d'", c);
1582 pr = 0;
1584 if (pr > priority)
1585 priority = pr;
1587 return priority;
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 == '%')
1601 p++;
1602 return 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,
1613 int *pout_reg)
1615 /* TODO: Simple constraints
1616 whitespace ignored
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
1630 J The integer 0.
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).
1638 ASMOperand *op;
1639 int sorted_op[MAX_ASM_OPERANDS];
1640 int i, j, k, p1, p2, tmp, reg, c, reg_mask;
1641 const char *str;
1642 uint8_t regs_allocated[NB_ASM_REGS];
1644 /* init fields */
1645 for (i = 0; i < nb_operands; i++) {
1646 op = &operands[i];
1647 op->input_index = -1;
1648 op->ref_index = -1;
1649 op->reg = -1;
1650 op->is_memory = 0;
1651 op->is_rw = 0;
1653 /* compute constraint priority and evaluate references to output
1654 constraints if input constraints */
1655 for (i = 0; i < nb_operands; i++) {
1656 op = &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')",
1664 i, str);
1665 op->ref_index = k;
1666 if (operands[k].input_index >= 0)
1667 tcc_error("cannot reference twice the same operand");
1668 operands[k].input_index = i;
1669 op->priority = 5;
1670 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
1671 && op->vt->sym
1672 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
1673 op->priority = 1;
1674 op->reg = reg;
1675 } else {
1676 op->priority = constraint_priority(str);
1680 /* sort operands according to their priority */
1681 for (i = 0; i < nb_operands; i++)
1682 sorted_op[i] = 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;
1687 if (p2 < p1) {
1688 tmp = sorted_op[i];
1689 sorted_op[i] = sorted_op[j];
1690 sorted_op[j] = tmp;
1695 for (i = 0; i < NB_ASM_REGS; i++) {
1696 if (clobber_regs[i])
1697 regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
1698 else
1699 regs_allocated[i] = 0;
1702 /* allocate registers and generate corresponding asm moves */
1703 for (i = 0; i < nb_operands; i++) {
1704 j = sorted_op[i];
1705 op = &operands[j];
1706 str = op->constraint;
1707 /* no need to allocate references */
1708 if (op->ref_index >= 0)
1709 continue;
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;
1715 } else {
1716 reg_mask = REG_IN_MASK;
1718 if (op->reg >= 0) {
1719 if (is_reg_allocated(op->reg))
1720 tcc_error
1721 ("asm regvar requests register that's taken already");
1722 reg = op->reg;
1724 try_next:
1725 c = *str++;
1726 switch (c) {
1727 case '=': // Operand is written-to
1728 goto try_next;
1729 case '+': // Operand is both READ and written-to
1730 op->is_rw = 1;
1731 /* FALL THRU */
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;
1736 goto try_next;
1737 case 'r': // general-purpose register
1738 case 'p': // loadable/storable address
1739 /* any general register */
1740 /* From a0 to a7 */
1741 if ((reg = op->reg) >= 0)
1742 goto reg_found;
1743 else for (reg = 10; reg <= 18; reg++) {
1744 if (!is_reg_allocated(reg))
1745 goto reg_found;
1747 goto try_next;
1748 reg_found:
1749 /* now we can reload in the register */
1750 op->is_llong = 0;
1751 op->reg = reg;
1752 regs_allocated[reg] |= reg_mask;
1753 break;
1754 case 'f': // floating pont register
1755 /* floating point register */
1756 /* From fa0 to fa7 */
1757 if ((reg = op->reg) >= 0)
1758 goto reg_found;
1759 else for (reg = 42; reg <= 50; reg++) {
1760 if (!is_reg_allocated(reg))
1761 goto reg_found;
1763 goto try_next;
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))
1767 goto try_next;
1768 break;
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
1778 later */
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))
1784 goto reg_found1;
1786 goto try_next;
1787 reg_found1:
1788 /* now we can reload in the register */
1789 regs_allocated[reg] |= REG_IN_MASK;
1790 op->reg = reg;
1791 op->is_memory = 1;
1794 break;
1795 default:
1796 tcc_error("asm constraint %d ('%s') could not be satisfied",
1797 j, op->constraint);
1798 break;
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) */
1809 *pout_reg = -1;
1810 for (i = 0; i < nb_operands; i++) {
1811 op = &operands[i];
1812 if (op->reg >= 0 &&
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))
1818 goto reg_found2;
1820 } else {
1821 /* From a0 to a7 */
1822 for (reg = 10; reg <= 18; reg++) {
1823 if (!(regs_allocated[reg] & REG_OUT_MASK))
1824 goto reg_found2;
1827 tcc_error("could not find free output register for reloading");
1828 reg_found2:
1829 *pout_reg = reg;
1830 break;
1834 /* print sorted constraints */
1835 #ifdef ASM_DEBUG
1836 for (i = 0; i < nb_operands; i++) {
1837 j = sorted_op[i];
1838 op = &operands[j];
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);
1844 if (*pout_reg >= 0)
1845 printf("out_reg=%d\n", *pout_reg);
1846 #endif
1849 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
1851 int reg;
1852 TokenSym *ts;
1854 if (!strcmp(str, "memory") ||
1855 !strcmp(str, "cc") ||
1856 !strcmp(str, "flags"))
1857 return;
1858 ts = tok_alloc(str, strlen(str));
1859 reg = asm_parse_regvar(ts->tok);
1860 if (reg == -1) {
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)
1870 return -1;
1872 if (t < TOK_ASM_f0)
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
1878 /* ABI mnemonic */
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 /*************************************************************/
1886 /* C extension */
1888 /* caller: Add funct6, funct2 into opcode */
1889 static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
1891 uint8_t dst, src;
1893 if (rd->type != OP_REG) {
1894 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1895 return;
1898 if (rs2->type != OP_REG) {
1899 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1900 return;
1903 /* subtract index of x8 */
1904 dst = rd->reg - 8;
1905 src = rs2->reg - 8;
1907 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
1908 if (dst > 7) {
1909 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1910 return;
1913 if (src > 7) {
1914 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1915 return;
1918 /* CA-type instruction:
1919 15...10 funct6
1920 9...7 rd'/rs1'
1921 6..5 funct2
1922 4...2 rs2'
1923 1...0 opcode */
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)
1930 uint32_t offset;
1931 uint8_t src;
1933 if (rs1->type != OP_REG) {
1934 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1935 return;
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));
1940 return;
1943 offset = imm->e.v;
1945 if (offset & 1) {
1946 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
1947 return;
1950 src = rs1->reg - 8;
1952 if (src > 7) {
1953 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1954 return;
1957 /* CB-type instruction:
1958 15...13 funct3
1959 12...10 offset
1960 9..7 rs1'
1961 6...2 offset
1962 1...0 opcode */
1964 /* non-branch also using CB:
1965 15...13 funct3
1966 12 imm
1967 11..10 funct2
1968 9...7 rd'/rs1'
1969 6..2 imm
1970 1...0 opcode */
1972 switch (token) {
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));
1976 return;
1977 default:
1978 gen_le16(opcode | C_ENCODE_RS1(src) | ((offset & 0x1f) << 2) | (NTH_BIT(offset, 5) << 12));
1979 return;
1983 static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
1985 uint32_t immediate;
1987 if (rd->type != OP_REG) {
1988 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1989 return;
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));
1994 return;
1997 immediate = imm->e.v;
1999 /* CI-type instruction:
2000 15...13 funct3
2001 12 imm
2002 11...7 rd/rs1
2003 6...2 imm
2004 1...0 opcode */
2006 switch (token) {
2007 case TOK_ASM_c_addi:
2008 case TOK_ASM_c_addiw:
2009 case TOK_ASM_c_li:
2010 case TOK_ASM_c_slli:
2011 gen_le16(opcode | ((immediate & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
2012 return;
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));
2015 return;
2016 case TOK_ASM_c_lui:
2017 gen_le16(opcode | (((immediate >> 12) & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 17) << 12));
2018 return;
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));
2022 return;
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));
2026 return;
2027 case TOK_ASM_c_nop:
2028 gen_le16(opcode);
2029 return;
2030 default:
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)
2038 uint32_t nzuimm;
2039 uint8_t dst;
2041 if (rd->type != OP_REG) {
2042 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
2043 return;
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));
2048 return;
2051 dst = rd->reg - 8;
2053 if (dst > 7) {
2054 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
2055 return;
2058 nzuimm = imm->e.v;
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));
2062 return;
2065 if (nzuimm & 3) {
2066 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token, NULL));
2067 return;
2070 /* CIW-type instruction:
2071 15...13 funct3
2072 12...5 imm
2073 4...2 rd'
2074 1...0 opcode */
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)
2082 uint32_t offset;
2084 /* +-2 KiB range */
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));
2087 return;
2090 offset = imm->e.v;
2092 if (offset & 1) {
2093 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
2094 return;
2097 /* CJ-type instruction:
2098 15...13 funct3
2099 12...2 offset[11|4|9:8|10|6|7|3:1|5]
2100 1...0 opcode */
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)
2108 uint32_t offset;
2109 uint8_t dst, src;
2111 if (rd->type != OP_REG) {
2112 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
2113 return;
2116 if (rs1->type != OP_REG) {
2117 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
2118 return;
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));
2123 return;
2126 dst = rd->reg - 8;
2127 src = rs1->reg - 8;
2129 if (dst > 7) {
2130 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
2131 return;
2134 if (src > 7) {
2135 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
2136 return;
2139 offset = imm->e.v;
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));
2143 return;
2146 if (offset & 3) {
2147 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
2148 return;
2151 /* CL-type instruction:
2152 15...13 funct3
2153 12...10 imm
2154 9...7 rs1'
2155 6...5 imm
2156 4...2 rd'
2157 1...0 opcode */
2159 switch (token) {
2160 /* imm variant 1 */
2161 case TOK_ASM_c_flw:
2162 case TOK_ASM_c_lw:
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));
2164 return;
2165 /* imm variant 2 */
2166 case TOK_ASM_c_fld:
2167 case TOK_ASM_c_ld:
2168 gen_le16(opcode | C_ENCODE_RS2(dst) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
2169 return;
2170 default:
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));
2180 return;
2183 if (rs2->type != OP_REG) {
2184 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
2185 return;
2188 /* CR-type instruction:
2189 15...12 funct4
2190 11..7 rd/rs1
2191 6...2 rs2
2192 1...0 opcode */
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)
2200 uint32_t offset;
2201 uint8_t base, src;
2203 if (rs2->type != OP_REG) {
2204 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
2205 return;
2208 if (rs1->type != OP_REG) {
2209 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
2210 return;
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));
2215 return;
2218 base = rs1->reg - 8;
2219 src = rs2->reg - 8;
2221 if (base > 7) {
2222 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
2223 return;
2226 if (src > 7) {
2227 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
2228 return;
2231 offset = imm->e.v;
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));
2235 return;
2238 if (offset & 3) {
2239 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
2240 return;
2243 /* CS-type instruction:
2244 15...13 funct3
2245 12...10 imm
2246 9...7 rs1'
2247 6...5 imm
2248 4...2 rs2'
2249 1...0 opcode */
2250 switch (token) {
2251 /* imm variant 1 */
2252 case TOK_ASM_c_fsw:
2253 case TOK_ASM_c_sw:
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));
2255 return;
2256 /* imm variant 2 */
2257 case TOK_ASM_c_fsd:
2258 case TOK_ASM_c_sd:
2259 gen_le16(opcode | C_ENCODE_RS2(base) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
2260 return;
2261 default:
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)
2269 uint32_t offset;
2271 if (rs2->type != OP_REG) {
2272 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
2273 return;
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));
2278 return;
2281 offset = imm->e.v;
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));
2285 return;
2288 if (offset & 3) {
2289 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
2290 return;
2293 /* CSS-type instruction:
2294 15...13 funct3
2295 12...7 imm
2296 6...2 rs2
2297 1...0 opcode */
2299 switch (token) {
2300 /* imm variant 1 */
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));
2304 return;
2305 /* imm variant 2 */
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));
2309 return;
2310 default:
2311 expect("known instruction");
2315 /*************************************************************/
2316 #endif /* ndef TARGET_DEFS_ONLY */