WAIT/POST_SEM(): generalize interface (and more)
[tinycc.git] / riscv64-asm.c
blob30662df6d2b6437e8e311bd48746a73ba9c227f8
1 /*************************************************************/
2 /*
3 * RISCV64 assembler for TCC
5 */
7 #ifdef TARGET_DEFS_ONLY
9 #define CONFIG_TCC_ASM
10 #define NB_ASM_REGS 32
12 ST_FUNC void g(int c);
13 ST_FUNC void gen_le16(int c);
14 ST_FUNC void gen_le32(int c);
16 /*************************************************************/
17 #else
18 /*************************************************************/
19 #define USING_GLOBALS
20 #include "tcc.h"
22 /* XXX: make it faster ? */
23 ST_FUNC void g(int c)
25 int ind1;
26 if (nocode_wanted)
27 return;
28 ind1 = ind + 1;
29 if (ind1 > cur_text_section->data_allocated)
30 section_realloc(cur_text_section, ind1);
31 cur_text_section->data[ind] = c;
32 ind = ind1;
35 ST_FUNC void gen_le16 (int i)
37 g(i);
38 g(i>>8);
41 ST_FUNC void gen_le32 (int i)
43 int ind1;
44 if (nocode_wanted)
45 return;
46 ind1 = ind + 4;
47 if (ind1 > cur_text_section->data_allocated)
48 section_realloc(cur_text_section, ind1);
49 cur_text_section->data[ind++] = i & 0xFF;
50 cur_text_section->data[ind++] = (i >> 8) & 0xFF;
51 cur_text_section->data[ind++] = (i >> 16) & 0xFF;
52 cur_text_section->data[ind++] = (i >> 24) & 0xFF;
55 ST_FUNC void gen_expr32(ExprValue *pe)
57 gen_le32(pe->v);
60 static void asm_emit_opcode(uint32_t opcode) {
61 gen_le32(opcode);
64 static void asm_nullary_opcode(TCCState *s1, int token)
66 switch (token) {
67 // Sync instructions
69 case TOK_ASM_fence: // I
70 asm_emit_opcode((0x3 << 2) | 3 | (0 << 12));
71 return;
72 case TOK_ASM_fence_i: // I
73 asm_emit_opcode((0x3 << 2) | 3| (1 << 12));
74 return;
76 // System calls
78 case TOK_ASM_scall: // I (pseudo)
79 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12));
80 return;
81 case TOK_ASM_sbreak: // I (pseudo)
82 asm_emit_opcode((0x1C << 2) | 3 | (0 << 12) | (1 << 20));
83 return;
85 // Privileged Instructions
87 case TOK_ASM_ecall:
88 asm_emit_opcode((0x1C << 2) | 3 | (0 << 20));
89 return;
90 case TOK_ASM_ebreak:
91 asm_emit_opcode((0x1C << 2) | 3 | (1 << 20));
92 return;
94 // Other
96 case TOK_ASM_wfi:
97 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
98 return;
100 default:
101 expect("nullary instruction");
105 enum {
106 OPT_REG,
107 OPT_IM12S,
108 OPT_IM32,
110 #define OP_REG (1 << OPT_REG)
111 #define OP_IM32 (1 << OPT_IM32)
112 #define OP_IM12S (1 << OPT_IM12S)
114 typedef struct Operand {
115 uint32_t type;
116 union {
117 uint8_t reg;
118 uint16_t regset;
119 ExprValue e;
121 } Operand;
123 /* Parse a text containing operand and store the result in OP */
124 static void parse_operand(TCCState *s1, Operand *op)
126 ExprValue e;
127 int8_t reg;
129 op->type = 0;
131 if ((reg = asm_parse_regvar(tok)) != -1) {
132 next(); // skip register name
133 op->type = OP_REG;
134 op->reg = (uint8_t) reg;
135 return;
136 } else if (tok == '$') {
137 /* constant value */
138 next(); // skip '#' or '$'
140 asm_expr(s1, &e);
141 op->type = OP_IM32;
142 op->e = e;
143 if (!op->e.sym) {
144 if ((int) op->e.v >= -2048 && (int) op->e.v < 2048)
145 op->type = OP_IM12S;
146 } else
147 expect("operand");
150 #define ENCODE_RS1(register_index) ((register_index) << 15)
151 #define ENCODE_RS2(register_index) ((register_index) << 20)
152 #define ENCODE_RD(register_index) ((register_index) << 7)
154 // Note: Those all map to CSR--so they are pseudo-instructions.
155 static void asm_unary_opcode(TCCState *s1, int token)
157 uint32_t opcode = (0x1C << 2) | 3 | (2 << 12);
158 Operand op;
159 parse_operand(s1, &op);
160 if (op.type != OP_REG) {
161 expect("register");
162 return;
164 opcode |= ENCODE_RD(op.reg);
166 switch (token) {
167 case TOK_ASM_rdcycle:
168 asm_emit_opcode(opcode | (0xC00 << 20));
169 return;
170 case TOK_ASM_rdcycleh:
171 asm_emit_opcode(opcode | (0xC80 << 20));
172 return;
173 case TOK_ASM_rdtime:
174 asm_emit_opcode(opcode | (0xC01 << 20) | ENCODE_RD(op.reg));
175 return;
176 case TOK_ASM_rdtimeh:
177 asm_emit_opcode(opcode | (0xC81 << 20) | ENCODE_RD(op.reg));
178 return;
179 case TOK_ASM_rdinstret:
180 asm_emit_opcode(opcode | (0xC02 << 20) | ENCODE_RD(op.reg));
181 return;
182 case TOK_ASM_rdinstreth:
183 asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
184 return;
185 default:
186 expect("unary instruction");
190 static void asm_emit_u(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
192 if (rd->type != OP_REG) {
193 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
194 return;
196 if (rs2->type != OP_IM12S && rs2->type != OP_IM32) {
197 tcc_error("'%s': Expected second source operand that is an immediate value", get_tok_str(token, NULL));
198 return;
199 } else if (rs2->e.v >= 0x100000) {
200 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 0xfffff", get_tok_str(token, NULL));
201 return;
203 /* U-type instruction:
204 31...12 imm[31:12]
205 11...7 rd
206 6...0 opcode */
207 gen_le32(opcode | ENCODE_RD(rd->reg) | (rs2->e.v << 12));
210 static void asm_binary_opcode(TCCState* s1, int token)
212 Operand ops[2];
213 parse_operand(s1, &ops[0]);
214 if (tok == ',')
215 next();
216 else
217 expect("','");
218 parse_operand(s1, &ops[1]);
220 switch (token) {
221 case TOK_ASM_lui:
222 asm_emit_u(token, (0xD << 2) | 3, &ops[0], &ops[1]);
223 return;
224 case TOK_ASM_auipc:
225 asm_emit_u(token, (0x05 << 2) | 3, &ops[0], &ops[1]);
226 return;
227 default:
228 expect("binary instruction");
232 /* caller: Add funct3, funct7 into opcode */
233 static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
235 if (rd->type != OP_REG) {
236 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
237 return;
239 if (rs1->type != OP_REG) {
240 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
241 return;
243 if (rs2->type != OP_REG) {
244 tcc_error("'%s': Expected second source operand that is a register or immediate", get_tok_str(token, NULL));
245 return;
247 /* R-type instruction:
248 31...25 funct7
249 24...20 rs2
250 19...15 rs1
251 14...12 funct3
252 11...7 rd
253 6...0 opcode */
254 gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
257 /* caller: Add funct3 into opcode */
258 static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
260 if (rd->type != OP_REG) {
261 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
262 return;
264 if (rs1->type != OP_REG) {
265 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
266 return;
268 if (rs2->type != OP_IM12S) {
269 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 4095", get_tok_str(token, NULL));
270 return;
272 /* I-type instruction:
273 31...20 imm[11:0]
274 19...15 rs1
275 14...12 funct3
276 11...7 rd
277 6...0 opcode */
279 gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | (rs2->e.v << 20));
282 static void asm_shift_opcode(TCCState *s1, int token)
284 Operand ops[3];
285 parse_operand(s1, &ops[0]);
286 if (tok == ',')
287 next();
288 else
289 expect("','");
290 parse_operand(s1, &ops[1]);
291 if (tok == ',')
292 next();
293 else
294 expect("','");
295 parse_operand(s1, &ops[2]);
297 switch (token) {
298 case TOK_ASM_sll:
299 asm_emit_r(token, (0xC << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
300 return;
301 case TOK_ASM_slli:
302 asm_emit_i(token, (4 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
303 return;
304 case TOK_ASM_srl:
305 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
306 return;
307 case TOK_ASM_srli:
308 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
309 return;
310 case TOK_ASM_sra:
311 asm_emit_r(token, (0xC << 2) | 3 | (5 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
312 return;
313 case TOK_ASM_srai:
314 asm_emit_i(token, (0x4 << 2) | 3 | (5 << 12) | (16 << 26), &ops[0], &ops[1], &ops[2]);
315 return;
316 case TOK_ASM_sllw:
317 asm_emit_r(token, (0xE << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
318 return;
319 case TOK_ASM_slliw:
320 asm_emit_i(token, (6 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
321 return;
322 case TOK_ASM_srlw:
323 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
324 return;
325 case TOK_ASM_srliw:
326 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
327 return;
328 case TOK_ASM_sraw:
329 asm_emit_r(token, (0xE << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
330 return;
331 case TOK_ASM_sraiw:
332 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
333 return;
334 default:
335 expect("shift instruction");
339 static void asm_data_processing_opcode(TCCState* s1, int token)
341 Operand ops[3];
342 parse_operand(s1, &ops[0]);
343 if (tok == ',')
344 next();
345 else
346 expect("','");
347 parse_operand(s1, &ops[1]);
348 if (tok == ',')
349 next();
350 else
351 expect("','");
352 parse_operand(s1, &ops[2]);
354 switch (token) {
355 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
357 case TOK_ASM_add:
358 asm_emit_r(token, (0xC << 2) | 3, &ops[0], &ops[1], &ops[2]);
359 return;
360 case TOK_ASM_addi:
361 asm_emit_i(token, (4 << 2) | 3, &ops[0], &ops[1], &ops[2]);
362 return;
363 case TOK_ASM_sub:
364 asm_emit_r(token, (0xC << 2) | 3 | (32 << 25), &ops[0], &ops[1], &ops[2]);
365 return;
366 case TOK_ASM_addw:
367 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
368 return;
369 case TOK_ASM_addiw: // 64 bit
370 asm_emit_i(token, (0x6 << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
371 return;
372 case TOK_ASM_subw:
373 asm_emit_r(token, (0xE << 2) | 3 | (0 << 12) | (32 << 25), &ops[0], &ops[1], &ops[2]);
374 return;
376 // Logical (RD,RS1,(RS2|IMM)); R-format or I-format
378 case TOK_ASM_xor:
379 asm_emit_r(token, (0xC << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
380 return;
381 case TOK_ASM_xori:
382 asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
383 return;
384 case TOK_ASM_or:
385 asm_emit_r(token, (0xC << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
386 return;
387 case TOK_ASM_ori:
388 asm_emit_i(token, (0x4 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
389 return;
390 case TOK_ASM_and:
391 asm_emit_r(token, (0xC << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
392 return;
393 case TOK_ASM_andi:
394 asm_emit_i(token, (0x4 << 2) | 3 | (7 << 12), &ops[0], &ops[1], &ops[2]);
395 return;
397 // Compare (RD,RS1,(RS2|IMM)); R-format or I-format
399 case TOK_ASM_slt:
400 asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
401 return;
402 case TOK_ASM_slti:
403 asm_emit_i(token, (0x4 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
404 return;
405 case TOK_ASM_sltu:
406 asm_emit_r(token, (0xC << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
407 return;
408 case TOK_ASM_sltiu:
409 asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
410 return;
411 default:
412 expect("known data processing instruction");
416 /* caller: Add funct3 to opcode */
417 static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
419 if (rs1->type != OP_REG) {
420 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
421 return;
423 if (rs2->type != OP_REG) {
424 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
425 return;
427 if (imm->type != OP_IM12S) {
428 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));
429 return;
432 uint16_t v = imm->e.v;
433 /* S-type instruction:
434 31...25 imm[11:5]
435 24...20 rs2
436 19...15 rs1
437 14...12 funct3
438 11...7 imm[4:0]
439 6...0 opcode
440 opcode always fixed pos. */
441 gen_le32(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | ((v & 0x1F) << 7) | ((v >> 5) << 25));
445 static void asm_data_transfer_opcode(TCCState* s1, int token)
447 Operand ops[3];
448 parse_operand(s1, &ops[0]);
449 if (ops[0].type != OP_REG) {
450 expect("register");
451 return;
453 if (tok == ',')
454 next();
455 else
456 expect("','");
457 parse_operand(s1, &ops[1]);
458 if (ops[1].type != OP_REG) {
459 expect("register");
460 return;
462 if (tok == ',')
463 next();
464 else
465 expect("','");
466 parse_operand(s1, &ops[2]);
468 switch (token) {
469 // Loads (RD,RS1,I); I-format
471 case TOK_ASM_lb:
472 asm_emit_i(token, (0x0 << 2) | 3, &ops[0], &ops[1], &ops[2]);
473 return;
474 case TOK_ASM_lh:
475 asm_emit_i(token, (0x0 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
476 return;
477 case TOK_ASM_lw:
478 asm_emit_i(token, (0x0 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
479 return;
480 case TOK_ASM_lbu:
481 asm_emit_i(token, (0x0 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &ops[2]);
482 return;
483 case TOK_ASM_lhu:
484 asm_emit_i(token, (0x0 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
485 return;
486 // 64 bit
487 case TOK_ASM_ld:
488 asm_emit_i(token, (0x0 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
489 return;
490 case TOK_ASM_lwu:
491 asm_emit_i(token, (0x0 << 2) | 3 | (6 << 12), &ops[0], &ops[1], &ops[2]);
492 return;
494 // Stores (RS1,RS2,I); S-format
496 case TOK_ASM_sb:
497 asm_emit_s(token, (0x8 << 2) | 3 | (0 << 12), &ops[0], &ops[1], &ops[2]);
498 return;
499 case TOK_ASM_sh:
500 asm_emit_s(token, (0x8 << 2) | 3 | (1 << 12), &ops[0], &ops[1], &ops[2]);
501 return;
502 case TOK_ASM_sw:
503 asm_emit_s(token, (0x8 << 2) | 3 | (2 << 12), &ops[0], &ops[1], &ops[2]);
504 return;
505 case TOK_ASM_sd:
506 asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
507 return;
509 default:
510 expect("known data transfer instruction");
514 static void asm_branch_opcode(TCCState* s1, int token)
516 // Branch (RS1,RS2,IMM); SB-format
517 uint32_t opcode = (0x18 << 2) | 3;
518 uint32_t offset = 0;
519 Operand ops[3];
520 parse_operand(s1, &ops[0]);
521 if (ops[0].type != OP_REG) {
522 expect("register");
523 return;
525 if (tok == ',')
526 next();
527 else
528 expect("','");
529 parse_operand(s1, &ops[1]);
530 if (ops[1].type != OP_REG) {
531 expect("register");
532 return;
534 if (tok == ',')
535 next();
536 else
537 expect("','");
538 parse_operand(s1, &ops[2]);
540 if (ops[2].type != OP_IM12S) {
541 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));
542 return;
544 offset = ops[2].e.v;
545 if (offset & 1) {
546 tcc_error("'%s': Expected third operand that is an even immediate value", get_tok_str(token, NULL));
547 return;
550 switch (token) {
551 case TOK_ASM_beq:
552 opcode |= 0 << 12;
553 break;
554 case TOK_ASM_bne:
555 opcode |= 1 << 12;
556 break;
557 case TOK_ASM_blt:
558 opcode |= 4 << 12;
559 break;
560 case TOK_ASM_bge:
561 opcode |= 5 << 12;
562 break;
563 case TOK_ASM_bltu:
564 opcode |= 6 << 12;
565 break;
566 case TOK_ASM_bgeu:
567 opcode |= 7 << 12;
568 break;
569 default:
570 expect("known branch instruction");
572 asm_emit_opcode(opcode | ENCODE_RS1(ops[0].reg) | ENCODE_RS2(ops[1].reg) | (((offset >> 1) & 0xF) << 8) | (((offset >> 5) & 0x1f) << 25) | (((offset >> 11) & 1) << 7) | (((offset >> 12) & 1) << 31));
575 ST_FUNC void asm_opcode(TCCState *s1, int token)
577 switch (token) {
578 case TOK_ASM_fence:
579 case TOK_ASM_fence_i:
580 case TOK_ASM_scall:
581 case TOK_ASM_sbreak:
582 case TOK_ASM_ecall:
583 case TOK_ASM_ebreak:
584 case TOK_ASM_mrts:
585 case TOK_ASM_mrth:
586 case TOK_ASM_hrts:
587 case TOK_ASM_wfi:
588 asm_nullary_opcode(s1, token);
589 return;
591 case TOK_ASM_rdcycle:
592 case TOK_ASM_rdcycleh:
593 case TOK_ASM_rdtime:
594 case TOK_ASM_rdtimeh:
595 case TOK_ASM_rdinstret:
596 case TOK_ASM_rdinstreth:
597 asm_unary_opcode(s1, token);
598 return;
600 case TOK_ASM_lui:
601 case TOK_ASM_auipc:
602 asm_binary_opcode(s1, token);
603 return;
605 case TOK_ASM_sll:
606 case TOK_ASM_slli:
607 case TOK_ASM_srl:
608 case TOK_ASM_srli:
609 case TOK_ASM_sra:
610 case TOK_ASM_srai:
611 case TOK_ASM_sllw:
612 case TOK_ASM_slld:
613 case TOK_ASM_slliw:
614 case TOK_ASM_sllid:
615 case TOK_ASM_srlw:
616 case TOK_ASM_srld:
617 case TOK_ASM_srliw:
618 case TOK_ASM_srlid:
619 case TOK_ASM_sraw:
620 case TOK_ASM_srad:
621 case TOK_ASM_sraiw:
622 case TOK_ASM_sraid:
623 asm_shift_opcode(s1, token);
624 return;
626 case TOK_ASM_add:
627 case TOK_ASM_addi:
628 case TOK_ASM_sub:
629 case TOK_ASM_addw:
630 case TOK_ASM_addd:
631 case TOK_ASM_addiw:
632 case TOK_ASM_addid:
633 case TOK_ASM_subw:
634 case TOK_ASM_subd:
635 case TOK_ASM_xor:
636 case TOK_ASM_xori:
637 case TOK_ASM_or:
638 case TOK_ASM_ori:
639 case TOK_ASM_and:
640 case TOK_ASM_andi:
641 case TOK_ASM_slt:
642 case TOK_ASM_slti:
643 case TOK_ASM_sltu:
644 case TOK_ASM_sltiu:
645 asm_data_processing_opcode(s1, token);
647 case TOK_ASM_lb:
648 case TOK_ASM_lh:
649 case TOK_ASM_lw:
650 case TOK_ASM_lbu:
651 case TOK_ASM_lhu:
652 case TOK_ASM_ld:
653 case TOK_ASM_lwu:
654 case TOK_ASM_sb:
655 case TOK_ASM_sh:
656 case TOK_ASM_sw:
657 case TOK_ASM_sd:
658 asm_data_transfer_opcode(s1, token);
659 return;
661 case TOK_ASM_beq:
662 case TOK_ASM_bne:
663 case TOK_ASM_blt:
664 case TOK_ASM_bge:
665 case TOK_ASM_bltu:
666 case TOK_ASM_bgeu:
667 asm_branch_opcode(s1, token);
668 return;
670 default:
671 expect("known instruction");
675 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
677 tcc_error("RISCV64 asm not implemented.");
680 /* generate prolog and epilog code for asm statement */
681 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
682 int nb_outputs, int is_output,
683 uint8_t *clobber_regs,
684 int out_reg)
688 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
689 int nb_operands, int nb_outputs,
690 const uint8_t *clobber_regs,
691 int *pout_reg)
695 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
697 int reg;
698 TokenSym *ts;
700 if (!strcmp(str, "memory") ||
701 !strcmp(str, "cc") ||
702 !strcmp(str, "flags"))
703 return;
704 ts = tok_alloc(str, strlen(str));
705 reg = asm_parse_regvar(ts->tok);
706 if (reg == -1) {
707 tcc_error("invalid clobber register '%s'", str);
709 clobber_regs[reg] = 1;
712 ST_FUNC int asm_parse_regvar (int t)
714 if (t >= TOK_ASM_x0 && t <= TOK_ASM_pc) { /* register name */
715 switch (t) {
716 case TOK_ASM_pc:
717 return -1; // TODO: Figure out where it can be used after all
718 default:
719 return t - TOK_ASM_x0;
721 } else
722 return -1;
725 /*************************************************************/
726 #endif /* ndef TARGET_DEFS_ONLY */