aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--i386-asm.c33
-rw-r--r--tcc.h8
-rw-r--r--tccgen.c20
-rw-r--r--tests/tcctest.c3
4 files changed, 58 insertions, 6 deletions
diff --git a/i386-asm.c b/i386-asm.c
index 16b2e91..a62a4cf 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -1185,6 +1185,28 @@ static const char *skip_constraint_modifiers(const char *p)
return p;
}
+/* If T (a token) is of the form "%reg" returns the register
+ number and type, otherwise return -1. */
+ST_FUNC int asm_parse_regvar (int t)
+{
+ const char *s;
+ Operand op;
+ if (t < TOK_IDENT)
+ return -1;
+ s = table_ident[t - TOK_IDENT]->str;
+ if (s[0] != '%')
+ return -1;
+ t = tok_alloc(s+1, strlen(s)-1)->tok;
+ unget_tok(t);
+ unget_tok('%');
+ parse_operand(tcc_state, &op);
+ /* Accept only integer regs for now. */
+ if (op.type & OP_REG)
+ return op.reg;
+ else
+ return -1;
+}
+
#define REG_OUT_MASK 0x01
#define REG_IN_MASK 0x02
@@ -1227,6 +1249,11 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands,
tcc_error("cannot reference twice the same operand");
operands[k].input_index = i;
op->priority = 5;
+ } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
+ && op->vt->sym
+ && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
+ op->priority = 1;
+ op->reg = reg;
} else {
op->priority = constraint_priority(str);
}
@@ -1274,6 +1301,12 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands,
} else {
reg_mask = REG_IN_MASK;
}
+ if (op->reg >= 0) {
+ if (is_reg_allocated(op->reg))
+ tcc_error("asm regvar requests register that's taken already");
+ reg = op->reg;
+ goto reg_found;
+ }
try_next:
c = *str++;
switch(c) {
diff --git a/tcc.h b/tcc.h
index 2434b94..fb104fa 100644
--- a/tcc.h
+++ b/tcc.h
@@ -372,7 +372,8 @@ typedef struct SValue {
unsigned short r2; /* second register, used for 'long long'
type. If not used, set to VT_CONST */
CValue c; /* constant, if VT_CONST */
- struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */
+ struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if
+ result of unary() for an identifier. */
} SValue;
struct Attribute {
@@ -407,7 +408,7 @@ typedef struct Sym {
int scope; /* scope level for locals */
};
union {
- long r; /* associated register */
+ long r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
struct Attribute a;
};
union {
@@ -416,7 +417,7 @@ typedef struct Sym {
};
CType type; /* associated type */
union {
- struct Sym *next; /* next related symbol */
+ struct Sym *next; /* next related symbol (for fields and anoms) */
long jnext; /* next jump label */
};
struct Sym *prev; /* prev symbol in stack */
@@ -1542,6 +1543,7 @@ ST_FUNC void gen_expr32(ExprValue *pe);
ST_FUNC void gen_expr64(ExprValue *pe);
#endif
ST_FUNC void asm_opcode(TCCState *s1, int opcode);
+ST_FUNC int asm_parse_regvar(int t);
ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);
ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
diff --git a/tccgen.c b/tccgen.c
index f7b7c2d..5c2acf8 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -386,7 +386,7 @@ ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c)
Sym *s;
s = sym_malloc();
- s->asm_label = 0;
+ s->scope = 0;
s->v = v;
s->type.t = t;
s->type.ref = NULL;
@@ -577,6 +577,7 @@ static void vsetc(CType *type, int r, CValue *vc)
vtop->r = r;
vtop->r2 = VT_CONST;
vtop->c = *vc;
+ vtop->sym = NULL;
}
/* push constant of type "type" with useless value */
@@ -4599,11 +4600,17 @@ ST_FUNC void unary(void)
r = VT_SYM | VT_CONST;
} else {
r = s->r;
+ /* A symbol that has a register is a local register variable,
+ which starts out as VT_LOCAL value. */
+ if ((r & VT_VALMASK) < VT_CONST)
+ r = (r & ~VT_VALMASK) | VT_LOCAL;
}
vset(&s->type, r, s->c);
- /* if forward reference, we must point to s */
+ /* Point to s as backpointer (even without r&VT_SYM).
+ Will be used by at least the x86 inline asm parser for
+ regvars. */
+ vtop->sym = s;
if (vtop->r & VT_SYM) {
- vtop->sym = s;
vtop->c.i = 0;
}
break;
@@ -6462,6 +6469,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
#endif
if (v) {
/* local variable */
+#ifdef CONFIG_TCC_ASM
+ if (ad->asm_label) {
+ int reg = asm_parse_regvar(ad->asm_label);
+ if (reg >= 0)
+ r = (r & ~VT_VALMASK) | reg;
+ }
+#endif
sym_push(v, type, r, addr);
} else {
/* push local reference */
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 5190523..d4a6a5a 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -2939,6 +2939,7 @@ void asm_test(void)
#ifdef BOOL_ISOC99
_Bool somebool;
#endif
+ register int regvar asm("%esi");
printf("inline asm:\n");
@@ -3001,6 +3002,8 @@ void asm_test(void)
val = 44;
fancy_copy2 (&val, &val2);
printf ("fancycpy2(%d)=%d\n", val, val2);
+ asm volatile ("mov $0x4243, %%esi" : "=r" (regvar));
+ printf ("regvar=%x\n", regvar);
return;
label1:
goto label2;