History

Support local register variables

Similar to GCC a local asm register variable enforces the use of a specified register in asm operands (and doesn't otherwise matter). Works only if the variable is directly mentioned as operand. For that we now generally store a backpointer from an SValue to a Sym when the SValue was the result of unary() parsing a symbol identifier.

Michael Matz committed 10 years ago

Commit f081acb1 parent 3bc9c324 files · +58 −6Browse files

Unified · Split

4 files
  1. i386-asm.c +33 −0
  2. tcc.h +5 −3
  3. tccgen.c +17 −3
  4. tests/tcctest.c +3 −0
i386-asm.c+33−0
@@ -1185,6 +1185,28 @@ static const char *skip_constraint_modifiers(const char *p) · 1184 unmodified lines
1185 return p;1185 return p;
1186}1186}
1187 1187
1188/* If T (a token) is of the form "%reg" returns the register
1189 number and type, otherwise return -1. */
1190ST_FUNC int asm_parse_regvar (int t)
1191{
1192 const char *s;
1193 Operand op;
1194 if (t < TOK_IDENT)
1195 return -1;
1196 s = table_ident[t - TOK_IDENT]->str;
1197 if (s[0] != '%')
1198 return -1;
1199 t = tok_alloc(s+1, strlen(s)-1)->tok;
1200 unget_tok(t);
1201 unget_tok('%');
1202 parse_operand(tcc_state, &op);
1203 /* Accept only integer regs for now. */
1204 if (op.type & OP_REG)
1205 return op.reg;
1206 else
1207 return -1;
1208}
1209
1188#define REG_OUT_MASK 0x011210#define REG_OUT_MASK 0x01
1189#define REG_IN_MASK 0x021211#define REG_IN_MASK 0x02
1190 1212
@@ -1227,6 +1249,11 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, · 36 unmodified lines
1227 tcc_error("cannot reference twice the same operand");1249 tcc_error("cannot reference twice the same operand");
1228 operands[k].input_index = i;1250 operands[k].input_index = i;
1229 op->priority = 5;1251 op->priority = 5;
1252 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
1253 && op->vt->sym
1254 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
1255 op->priority = 1;
1256 op->reg = reg;
1230 } else {1257 } else {
1231 op->priority = constraint_priority(str);1258 op->priority = constraint_priority(str);
1232 }1259 }
@@ -1274,6 +1301,12 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, · 41 unmodified lines
1274 } else {1301 } else {
1275 reg_mask = REG_IN_MASK;1302 reg_mask = REG_IN_MASK;
1276 }1303 }
1304 if (op->reg >= 0) {
1305 if (is_reg_allocated(op->reg))
1306 tcc_error("asm regvar requests register that's taken already");
1307 reg = op->reg;
1308 goto reg_found;
1309 }
1277 try_next:1310 try_next:
1278 c = *str++;1311 c = *str++;
1279 switch(c) {1312 switch(c) {
tcc.h+5−3
@@ -372,7 +372,8 @@ typedef struct SValue { · 371 unmodified lines
372 unsigned short r2; /* second register, used for 'long long'372 unsigned short r2; /* second register, used for 'long long'
373 type. If not used, set to VT_CONST */373 type. If not used, set to VT_CONST */
374 CValue c; /* constant, if VT_CONST */374 CValue c; /* constant, if VT_CONST */
375 struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */375 struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if
376 result of unary() for an identifier. */
376} SValue;377} SValue;
377 378
378struct Attribute {379struct Attribute {
@@ -407,7 +408,7 @@ typedef struct Sym { · 28 unmodified lines
407 int scope; /* scope level for locals */408 int scope; /* scope level for locals */
408 };409 };
409 union {410 union {
410 long r; /* associated register */411 long r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
411 struct Attribute a;412 struct Attribute a;
412 };413 };
413 union {414 union {
@@ -416,7 +417,7 @@ typedef struct Sym { · 2 unmodified lines
416 };417 };
417 CType type; /* associated type */418 CType type; /* associated type */
418 union {419 union {
419 struct Sym *next; /* next related symbol */420 struct Sym *next; /* next related symbol (for fields and anoms) */
420 long jnext; /* next jump label */421 long jnext; /* next jump label */
421 };422 };
422 struct Sym *prev; /* prev symbol in stack */423 struct Sym *prev; /* prev symbol in stack */
@@ -1542,6 +1543,7 @@ ST_FUNC void gen_expr32(ExprValue *pe); · 1119 unmodified lines
1542ST_FUNC void gen_expr64(ExprValue *pe);1543ST_FUNC void gen_expr64(ExprValue *pe);
1543#endif1544#endif
1544ST_FUNC void asm_opcode(TCCState *s1, int opcode);1545ST_FUNC void asm_opcode(TCCState *s1, int opcode);
1546ST_FUNC int asm_parse_regvar(int t);
1545ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);1547ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);
1546ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier);1548ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
1547ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);1549ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
tccgen.c+17−3
@@ -386,7 +386,7 @@ ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c) · 385 unmodified lines
386 Sym *s;386 Sym *s;
387 387
388 s = sym_malloc();388 s = sym_malloc();
389 s->asm_label = 0;389 s->scope = 0;
390 s->v = v;390 s->v = v;
391 s->type.t = t;391 s->type.t = t;
392 s->type.ref = NULL;392 s->type.ref = NULL;
@@ -577,6 +577,7 @@ static void vsetc(CType *type, int r, CValue *vc) · 184 unmodified lines
577 vtop->r = r;577 vtop->r = r;
578 vtop->r2 = VT_CONST;578 vtop->r2 = VT_CONST;
579 vtop->c = *vc;579 vtop->c = *vc;
580 vtop->sym = NULL;
580}581}
581 582
582/* push constant of type "type" with useless value */583/* push constant of type "type" with useless value */
@@ -4599,11 +4600,17 @@ ST_FUNC void unary(void) · 4016 unmodified lines
4599 r = VT_SYM | VT_CONST;4600 r = VT_SYM | VT_CONST;
4600 } else {4601 } else {
4601 r = s->r;4602 r = s->r;
4603 /* A symbol that has a register is a local register variable,
4604 which starts out as VT_LOCAL value. */
4605 if ((r & VT_VALMASK) < VT_CONST)
4606 r = (r & ~VT_VALMASK) | VT_LOCAL;
4602 }4607 }
4603 vset(&s->type, r, s->c);4608 vset(&s->type, r, s->c);
4604 /* if forward reference, we must point to s */4609 /* Point to s as backpointer (even without r&VT_SYM).
4610 Will be used by at least the x86 inline asm parser for
4611 regvars. */
4612 vtop->sym = s;
4605 if (vtop->r & VT_SYM) {4613 if (vtop->r & VT_SYM) {
4606 vtop->sym = s;
4607 vtop->c.i = 0;4614 vtop->c.i = 0;
4608 }4615 }
4609 break;4616 break;
@@ -6462,6 +6469,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 1852 unmodified lines
6462#endif6469#endif
6463 if (v) {6470 if (v) {
6464 /* local variable */6471 /* local variable */
6472#ifdef CONFIG_TCC_ASM
6473 if (ad->asm_label) {
6474 int reg = asm_parse_regvar(ad->asm_label);
6475 if (reg >= 0)
6476 r = (r & ~VT_VALMASK) | reg;
6477 }
6478#endif
6465 sym_push(v, type, r, addr);6479 sym_push(v, type, r, addr);
6466 } else {6480 } else {
6467 /* push local reference */6481 /* push local reference */
tests/tcctest.c+3−0
@@ -2939,6 +2939,7 @@ void asm_test(void) · 2938 unmodified lines
2939#ifdef BOOL_ISOC992939#ifdef BOOL_ISOC99
2940 _Bool somebool;2940 _Bool somebool;
2941#endif2941#endif
2942 register int regvar asm("%esi");
2942 2943
2943 printf("inline asm:\n");2944 printf("inline asm:\n");
2944 2945
@@ -3001,6 +3002,8 @@ void asm_test(void) · 56 unmodified lines
3001 val = 44;3002 val = 44;
3002 fancy_copy2 (&val, &val2);3003 fancy_copy2 (&val, &val2);
3003 printf ("fancycpy2(%d)=%d\n", val, val2);3004 printf ("fancycpy2(%d)=%d\n", val, val2);
3005 asm volatile ("mov $0x4243, %%esi" : "=r" (regvar));
3006 printf ("regvar=%x\n", regvar);
3004 return;3007 return;
3005 label1:3008 label1:
3006 goto label2;3009 goto label2;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t