aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--i386-gen.c114
-rw-r--r--tcc.c481
2 files changed, 296 insertions, 299 deletions
diff --git a/i386-gen.c b/i386-gen.c
index 40f1c2d..163180b 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -276,13 +276,14 @@ void gfunc_start(GFuncContext *c)
c->args_size = 0;
}
-/* push function parameter which is in (vt, vc) */
+/* push function parameter which is in (vtop->t, vtop->c). Stack entry
+ is then popped. */
void gfunc_param(GFuncContext *c)
{
- int size, align, ft, fc, r;
+ int size, align, r;
- if ((vt & (VT_BTYPE | VT_LVAL)) == (VT_STRUCT | VT_LVAL)) {
- size = type_size(vt, &align);
+ if ((vtop->t & (VT_BTYPE | VT_LVAL)) == (VT_STRUCT | VT_LVAL)) {
+ size = type_size(vtop->t, &align);
/* align to stack align size */
size = (size + 3) & ~3;
/* allocate the necessary size on stack */
@@ -291,21 +292,17 @@ void gfunc_param(GFuncContext *c)
r = get_reg(REG_CLASS_INT);
o(0x89); /* mov %esp, r */
o(0xe0 + r);
- ft = vt;
- fc = vc;
vset(VT_INT | r, 0);
- vpush();
- vt = ft;
- vc = fc;
+ vswap();
vstore();
c->args_size += size;
- } else if ((vt & VT_BTYPE) == VT_LDOUBLE ||
- (vt & VT_BTYPE) == VT_DOUBLE ||
- (vt & VT_BTYPE) == VT_FLOAT) {
+ } else if ((vtop->t & VT_BTYPE) == VT_LDOUBLE ||
+ (vtop->t & VT_BTYPE) == VT_DOUBLE ||
+ (vtop->t & VT_BTYPE) == VT_FLOAT) {
gv(); /* only one float register */
- if ((vt & VT_BTYPE) == VT_FLOAT)
+ if ((vtop->t & VT_BTYPE) == VT_FLOAT)
size = 4;
- else if ((vt & VT_BTYPE) == VT_DOUBLE)
+ else if ((vtop->t & VT_BTYPE) == VT_DOUBLE)
size = 8;
else
size = 12;
@@ -324,21 +321,22 @@ void gfunc_param(GFuncContext *c)
o(0x50 + r); /* push r */
c->args_size += 4;
}
+ vtop--;
}
-/* generate function call with address in (vt, vc) and free function
- context */
+/* generate function call with address in (vtop->t, vtop->c) and free function
+ context. Stack entry is popped */
void gfunc_call(GFuncContext *c)
{
int r;
- if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+ if ((vtop->t & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */
/* forward reference */
- if (vt & VT_FORWARD) {
- greloc((Sym *)vc, ind + 1, RELOC_REL32);
+ if (vtop->t & VT_FORWARD) {
+ greloc((Sym *)vtop->c, ind + 1, RELOC_REL32);
oad(0xe8, 0);
} else {
- oad(0xe8, vc - ind - 5);
+ oad(0xe8, vtop->c - ind - 5);
}
} else {
/* otherwise, indirect call */
@@ -348,6 +346,7 @@ void gfunc_call(GFuncContext *c)
}
if (c->args_size)
oad(0xc481, c->args_size); /* add $xxx, %esp */
+ vtop--;
}
int gjmp(int t)
@@ -355,31 +354,31 @@ int gjmp(int t)
return psym(0xe9, t);
}
-/* generate a test. set 'inv' to invert test */
+/* generate a test. set 'inv' to invert test. Stack entry is popped */
int gtst(int inv, int t)
{
int v, *p;
- v = vt & VT_VALMASK;
+ v = vtop->t & VT_VALMASK;
if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
g(0x0f);
- t = psym((vc - 16) ^ inv, t);
+ t = psym((vtop->c - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {
- /* insert vc jump list in t */
- p = &vc;
+ /* insert vtop->c jump list in t */
+ p = &vtop->c;
while (*p != 0)
p = (int *)*p;
*p = t;
- t = vc;
+ t = vtop->c;
} else {
t = gjmp(t);
- gsym(vc);
+ gsym(vtop->c);
}
- } else if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+ } else if ((vtop->t & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant jmp optimization */
- if ((vc != 0) != inv)
+ if ((vtop->c != 0) != inv)
t = gjmp(t);
} else {
/* XXX: floats */
@@ -389,14 +388,21 @@ int gtst(int inv, int t)
g(0x0f);
t = psym(0x85 ^ inv, t);
}
+ vtop--;
return t;
}
-/* generate an integer binary operation 'v = r op fr' instruction and
- modifies (vt,vc) if needed */
-void gen_opi(int op, int r, int fr)
+/* generate an integer binary operation */
+void gen_opi(int op)
{
- int t;
+ int t, r, fr;
+
+ vswap();
+ r = gv();
+ vswap();
+ fr = gv();
+ vtop--;
+
if (op == '+') {
o(0x01);
o(0xc0 + r + fr * 8);
@@ -433,7 +439,7 @@ void gen_opi(int op, int r, int fr)
o(0xe8 + r);
else
o(0xf8 + r);
- vt = (vt & VT_TYPE) | r;
+ vtop->t = (vtop->t & VT_TYPE) | r;
} else if (op == '/' | op == TOK_UDIV | op == TOK_PDIV |
op == '%' | op == TOK_UMOD) {
save_reg(2); /* save edx */
@@ -450,33 +456,32 @@ void gen_opi(int op, int r, int fr)
r = 2;
else
r = 0;
- vt = (vt & VT_TYPE) | r;
+ vtop->t = (vtop->t & VT_TYPE) | r;
} else {
+ vtop--;
o(0x39);
o(0xc0 + r + fr * 8); /* cmp fr, r */
vset(VT_CMP, op);
}
}
-/* generate a floating point operation 'v = t1 op t2' instruction and
- modifies (vt,vc) if needed */
-/* NOTE: floats can only be lvalues */
+/* generate a floating point operation 'v = t1 op t2' instruction. The
+ two operands are guaranted to have the same floating point type */
+/* NOTE: currently floats can only be lvalues */
void gen_opf(int op)
{
int a, ft, fc, swapped, r;
/* must put at least one value in the floating point register */
- if ((vstack_ptr[-4] & VT_LVAL) &&
- (vstack_ptr[-2] & VT_LVAL)) {
+ if ((vtop[-1].t & VT_LVAL) &&
+ (vtop[0].t & VT_LVAL)) {
vswap();
- vpop(&vt, &vc);
gv();
- vpush();
vswap();
}
if (op >= TOK_EQ && op <= TOK_GT) {
/* load on stack second operand */
- load(REG_ST0, vstack_ptr[-2], vstack_ptr[-1]);
+ load(REG_ST0, vtop->t, vtop->c);
if (op == TOK_GE || op == TOK_GT)
o(0xc9d9); /* fxch %st(1) */
o(0xe9da); /* fucompp */
@@ -495,13 +500,14 @@ void gen_opf(int op)
o(0x45c4f6); /* test $0x45, %ah */
op = TOK_EQ;
}
- vstack_ptr[-4] = (vstack_ptr[-4] & VT_TYPE) | VT_CMP;
- vstack_ptr[-3] = op;
+ vtop--;
+ vtop->t = (vtop->t & VT_TYPE) | VT_CMP;
+ vtop->c = op;
} else {
/* swap the stack if needed so that t1 is the register and t2 is
the memory reference */
swapped = 0;
- if (vstack_ptr[-4] & VT_LVAL) {
+ if (vtop[-1].t & VT_LVAL) {
vswap();
swapped = 1;
}
@@ -525,8 +531,8 @@ void gen_opf(int op)
a += 8;
break;
}
- ft = vstack_ptr[-2];
- fc = vstack_ptr[-1];
+ ft = vtop->t;
+ fc = vtop->c;
if ((ft & VT_BTYPE) == VT_DOUBLE)
o(0xdc);
else
@@ -541,24 +547,24 @@ void gen_opf(int op)
} else {
g(0x00 + a + r);
}
+ vtop--;
}
- vstack_ptr -= 2;
- vpop(&vt, &vc);
}
-/* convert integers to floating point (float or double) */
+/* convert integers to floating point 't' type (float/double/long
+ double) */
void gen_cvtf(int t)
{
- if ((vt & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) {
+ if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) {
/* unsigned int to float/double/long double */
o(0x6a); /* push $0 */
g(0x00);
- o(0x50 + (vt & VT_VALMASK)); /* push r */
+ o(0x50 + (vtop->t & VT_VALMASK)); /* push r */
o(0x242cdf); /* fildll (%esp) */
o(0x08c483); /* add $8, %esp */
} else {
/* int to float/double/long double */
- o(0x50 + (vt & VT_VALMASK)); /* push r */
+ o(0x50 + (vtop->t & VT_VALMASK)); /* push r */
o(0x2404db); /* fildl (%esp) */
o(0x04c483); /* add $4, %esp */
}
diff --git a/tcc.c b/tcc.c
index edeb46d..2a1f251 100644
--- a/tcc.c
+++ b/tcc.c
@@ -64,6 +64,12 @@ typedef union CValue {
int tab[1];
} CValue;
+/* value on stack */
+typedef struct SValue {
+ int t;
+ int c;
+} SValue;
+
/* symbol management */
typedef struct Sym {
int v; /* symbol token */
@@ -114,6 +120,7 @@ typedef struct {
/* parser */
FILE *file;
+int line_num;
int ch, ch1, tok, tok1;
CValue tokc, tok1c;
@@ -125,7 +132,7 @@ CValue tokc, tok1c;
anon_sym: anonymous symbol index
*/
int rsym, anon_sym,
- prog, ind, loc, glo, vt, vc, const_wanted, line_num;
+ prog, ind, loc, glo, const_wanted;
int global_expr; /* true if compound literals must be allocated
globally (used during initializers parsing */
int func_vt, func_vc; /* current function return type (used by
@@ -139,7 +146,7 @@ char *filename, *funcname;
SymStack extern_stack;
SymStack define_stack, global_stack, local_stack, label_stack;
-int vstack[VSTACK_SIZE], *vstack_ptr;
+SValue vstack[VSTACK_SIZE], *vtop;
int *macro_ptr, *macro_ptr_allocated;
IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
@@ -332,9 +339,9 @@ int decl_initializer_alloc(int t, int has_init);
int gv(void);
void move_reg(int r, int s);
void save_reg(int r);
-void vpush(void);
-void vpop(int *ft, int *fc);
+void vpop(void);
void vswap(void);
+void vdup(void);
int get_reg(int rc);
void macro_subst(int **tok_str, int *tok_len,
@@ -460,7 +467,7 @@ void skip(int c)
void test_lvalue(void)
{
- if (!(vt & VT_LVAL))
+ if (!(vtop->t & VT_LVAL))
expect("lvalue");
}
@@ -930,7 +937,7 @@ void define_symbol(char *sym)
sym_push1(&define_stack, ts->tok, MACRO_OBJ, (int)str);
}
-void preprocess()
+void preprocess(void)
{
int size, i, c, v, t, *str, len;
char buf[1024], *q, *p;
@@ -1853,13 +1860,43 @@ void swap(int *p, int *q)
void vset(int t, int v)
{
- vt = t;
- vc = v;
+ if (vtop >= vstack + VSTACK_SIZE)
+ error("memory full");
+ /* cannot let cpu flags if other instruction are generated */
+ /* XXX: VT_JMP test too ? */
+ if ((vtop->t & VT_VALMASK) == VT_CMP)
+ gv();
+ vtop++;
+ vtop->t = t;
+ vtop->c = v;
+}
+
+void vpop(void)
+{
+ vtop--;
+}
+
+void vswap(void)
+{
+ SValue tmp;
+
+ tmp = vtop[0];
+ vtop[0] = vtop[-1];
+ vtop[-1] = tmp;
+}
+
+void vdup(void)
+{
+ if (vtop >= vstack + VSTACK_SIZE)
+ error("memory full");
+ vtop++;
+ *vtop = vtop[-1];
}
int save_reg_forced(int r)
{
- int i, l, *p, t;
+ int i, l, t;
+ SValue *p;
/* store register */
loc = (loc - 4) & -3;
@@ -1867,15 +1904,15 @@ int save_reg_forced(int r)
l = loc;
/* modify all stack values */
- for(p=vstack;p<vstack_ptr;p+=2) {
- i = p[0] & VT_VALMASK;
+ for(p=vstack;p<=vtop;p++) {
+ i = p->t & VT_VALMASK;
if (i == r) {
- if (p[0] & VT_LVAL)
+ if (p->t & VT_LVAL)
t = VT_LLOCAL;
else
t = VT_LOCAL;
- p[0] = (p[0] & VT_TYPE) | VT_LVAL | t;
- p[1] = l;
+ p->t = (p->t & VT_TYPE) | VT_LVAL | t;
+ p->c = l;
}
}
return l;
@@ -1884,11 +1921,12 @@ int save_reg_forced(int r)
/* save r to memory. and mark it as being free */
void save_reg(int r)
{
- int i, *p;
+ int i;
+ SValue *p;
/* modify all stack values */
- for(p=vstack;p<vstack_ptr;p+=2) {
- i = p[0] & VT_VALMASK;
+ for(p=vstack;p<=vtop;p++) {
+ i = p->t & VT_VALMASK;
if (i == r) {
save_reg_forced(r);
break;
@@ -1899,13 +1937,14 @@ void save_reg(int r)
/* find a free register of class 'rc'. If none, save one register */
int get_reg(int rc)
{
- int r, i, *p;
+ int r, i;
+ SValue *p;
/* find a free register */
for(r=0;r<NB_REGS;r++) {
if (reg_classes[r] & rc) {
- for(p=vstack;p<vstack_ptr;p+=2) {
- i = p[0] & VT_VALMASK;
+ for(p=vstack;p<=vtop;p++) {
+ i = p->t & VT_VALMASK;
if (i == r)
goto notfound;
}
@@ -1917,8 +1956,8 @@ int get_reg(int rc)
/* no register left : free the first one on the stack (very
important to start from the bottom to ensure that we don't
spill registers used in gen_op()) */
- for(p=vstack;p<vstack_ptr;p+=2) {
- r = p[0] & VT_VALMASK;
+ for(p=vstack;p<=vtop;p++) {
+ r = p->t & VT_VALMASK;
if (r < VT_CONST && (reg_classes[r] & rc)) {
save_reg(r);
break;
@@ -1929,9 +1968,11 @@ int get_reg(int rc)
void save_regs()
{
- int r, *p;
- for(p=vstack;p<vstack_ptr;p+=2) {
- r = p[0] & VT_VALMASK;
+ int r;
+ SValue *p;
+
+ for(p=vstack;p<=vtop;p++) {
+ r = p->t & VT_VALMASK;
if (r < VT_CONST) {
save_reg(r);
}
@@ -1948,130 +1989,96 @@ void move_reg(int r, int s)
}
}
-/* convert a (vt, vc) in register. lvalues are converted as
+/* convert a (vtop->t, vtop->c) in register. lvalues are converted as
values. Cannot be used if cannot be converted to register value
(such as structures). */
-int gvp(void)
+int gv(void)
{
int r, bit_pos, bit_size, rc;
/* NOTE: get_reg can modify vstack[] */
- if (vt & VT_BITFIELD) {
- bit_pos = (vt >> VT_STRUCT_SHIFT) & 0x3f;
- bit_size = (vt >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
+ if (vtop->t & VT_BITFIELD) {
+ bit_pos = (vtop->t >> VT_STRUCT_SHIFT) & 0x3f;
+ bit_size = (vtop->t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
/* remove bit field info to avoid loops */
- vt &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
+ vtop->t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
/* generate shifts */
- vpush();
vset(VT_CONST, 32 - (bit_pos + bit_size));
gen_op(TOK_SHL);
- vpush();
vset(VT_CONST, 32 - bit_size);
/* NOTE: transformed to SHR if unsigned */
gen_op(TOK_SAR);
r = gv();
} else {
- r = vt & VT_VALMASK;
- if (r >= VT_CONST || (vt & VT_LVAL)) {
- if ((vt & VT_BTYPE) == VT_FLOAT ||
- (vt & VT_BTYPE) == VT_DOUBLE)
+ r = vtop->t & VT_VALMASK;
+ if (r >= VT_CONST || (vtop->t & VT_LVAL)) {
+ if ((vtop->t & VT_BTYPE) == VT_FLOAT ||
+ (vtop->t & VT_BTYPE) == VT_DOUBLE)
rc = REG_CLASS_FLOAT;
else
rc = REG_CLASS_INT;
r = get_reg(rc);
}
- load(r, vt, vc);
- vt = (vt & VT_TYPE) | r;
+ load(r, vtop->t, vtop->c);
+ vtop->t = (vtop->t & VT_TYPE) | r;
}
return r;
}
-void vpush(void)
-{
- if (vstack_ptr >= vstack + VSTACK_SIZE)
- error("memory full");
- /* cannot let cpu flags if other instruction are generated */
- /* XXX: VT_JMP test too ? */
- if ((vt & VT_VALMASK) == VT_CMP)
- gvp();
- *vstack_ptr++ = vt;
- *vstack_ptr++ = vc;
-}
-
-void vpop(int *ft, int *fc)
-{
- *fc = *--vstack_ptr;
- *ft = *--vstack_ptr;
-}
-
-void vswap(void)
-{
- swap(vstack_ptr - 4, vstack_ptr - 2);
- swap(vstack_ptr - 3, vstack_ptr - 1);
-}
-
-/* generate a value in a register from vt and vc */
-int gv(void)
-{
- int r;
- vpush(); /* need so that gvp does not allocate the register we
- currently use */
- r = gvp();
- vstack_ptr -= 2;
- return r;
-}
-
/* handle constant optimizations and various machine independant opt */
void gen_opc(int op)
{
- int fr, ft, fc, r, c1, c2, n;
+ int fc, c1, c2, n;
+ SValue *v1, *v2;
- vpop(&ft, &fc);
- vpop(&vt, &vc);
+ v1 = vtop - 1;
+ v2 = vtop;
/* currently, we cannot do computations with forward symbols */
- c1 = (vt & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST;
- c2 = (ft & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST;
+ c1 = (v1->t & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST;
+ c2 = (v2->t & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST;
if (c1 && c2) {
+ fc = v2->c;
switch(op) {
- case '+': vc += fc; break;
- case '-': vc -= fc; break;
- case '&': vc &= fc; break;
- case '^': vc ^= fc; break;
- case '|': vc |= fc; break;
- case '*': vc *= fc; break;
+ case '+': v1->c += fc; break;
+ case '-': v1->c -= fc; break;
+ case '&': v1->c &= fc; break;
+ case '^': v1->c ^= fc; break;
+ case '|': v1->c |= fc; break;
+ case '*': v1->c *= fc; break;
case TOK_PDIV:
- case '/': vc /= fc; break; /* XXX: zero case ? */
- case '%': vc %= fc; break; /* XXX: zero case ? */
- case TOK_UDIV: vc = (unsigned)vc / fc; break; /* XXX: zero case ? */
- case TOK_UMOD: vc = (unsigned)vc % fc; break; /* XXX: zero case ? */
- case TOK_SHL: vc <<= fc; break;
- case TOK_SHR: vc = (unsigned)vc >> fc; break;
- case TOK_SAR: vc >>= fc; break;
+ case '/': v1->c /= fc; break; /* XXX: zero case ? */
+ case '%': v1->c %= fc; break; /* XXX: zero case ? */
+ case TOK_UDIV: v1->c = (unsigned)v1->c / fc; break; /* XXX: zero case ? */
+ case TOK_UMOD: v1->c = (unsigned)v1->c % fc; break; /* XXX: zero case ? */
+ case TOK_SHL: v1->c <<= fc; break;
+ case TOK_SHR: v1->c = (unsigned)v1->c >> fc; break;
+ case TOK_SAR: v1->c >>= fc; break;
/* tests */
- case TOK_ULT: vc = (unsigned)vc < (unsigned)fc; break;
- case TOK_UGE: vc = (unsigned)vc >= (unsigned)fc; break;
- case TOK_EQ: vc = vc == fc; break;
- case TOK_NE: vc = vc != fc; break;
- case TOK_ULE: vc = (unsigned)vc <= (unsigned)fc; break;
- case TOK_UGT: vc = (unsigned)vc > (unsigned)fc; break;
- case TOK_LT: vc = vc < fc; break;
- case TOK_GE: vc = vc >= fc; break;
- case TOK_LE: vc = vc <= fc; break;
- case TOK_GT: vc = vc > fc; break;
+ case TOK_ULT: v1->c = (unsigned)v1->c < (unsigned)fc; break;
+ case TOK_UGE: v1->c = (unsigned)v1->c >= (unsigned)fc; break;
+ case TOK_EQ: v1->c = v1->c == fc; break;
+ case TOK_NE: v1->c = v1->c != fc; break;
+ case TOK_ULE: v1->c = (unsigned)v1->c <= (unsigned)fc; break;
+ case TOK_UGT: v1->c = (unsigned)v1->c > (unsigned)fc; break;
+ case TOK_LT: v1->c = v1->c < fc; break;
+ case TOK_GE: v1->c = v1->c >= fc; break;
+ case TOK_LE: v1->c = v1->c <= fc; break;
+ case TOK_GT: v1->c = v1->c > fc; break;
/* logical */
- case TOK_LAND: vc = vc && fc; break;
- case TOK_LOR: vc = vc || fc; break;
+ case TOK_LAND: v1->c = v1->c && fc; break;
+ case TOK_LOR: v1->c = v1->c || fc; break;
default:
goto general_case;
}
+ vtop--;
} else {
/* if commutative ops, put c2 as constant */
if (c1 && (op == '+' || op == '&' || op == '^' ||
op == '|' || op == '*')) {
- swap(&vt, &ft);
- swap(&vc, &fc);
+ vswap();
swap(&c1, &c2);
}
+ fc = vtop->c;
if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV ||
op == TOK_PDIV) &&
fc == 1) ||
@@ -2080,6 +2087,8 @@ void gen_opc(int op)
fc == 0) ||
(op == '&' &&
fc == -1))) {
+ /* nothing to do */
+ vtop--;
} else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
/* try to use shifts instead of muls or divs */
if (fc > 0 && (fc & (fc - 1)) == 0) {
@@ -2088,7 +2097,7 @@ void gen_opc(int op)
fc >>= 1;
n++;
}
- fc = n;
+ vtop->c = n;
if (op == '*')
op = TOK_SHL;
else if (op == TOK_PDIV)
@@ -2099,20 +2108,9 @@ void gen_opc(int op)
goto general_case;
} else {
general_case:
- vpush();
- vt = ft;
- vc = fc;
-
- fr = gv(); /* second operand */
- vpop(&ft, &fc);
- vpush();
- vt = ft;
- vc = fc;
- r = gv(); /* first operand */
- vpop(&ft, &fc);
-
/* call low level op generator */
- gen_opi(op, r, fr);
+ /* XXX: remove explicit registers */
+ gen_opi(op);
}
}
}
@@ -2135,9 +2133,8 @@ void gen_op(int op)
{
int u, t1, t2, bt1, bt2, t;
- vpush();
- t1 = vstack_ptr[-4];
- t2 = vstack_ptr[-2];
+ t1 = vtop[-1].t;
+ t2 = vtop[0].t;
bt1 = t1 & VT_BTYPE;
bt2 = t2 & VT_BTYPE;
@@ -2153,26 +2150,22 @@ void gen_op(int op)
if (op != '+' && op != '-' && op != '*' && op != '/' &&
op < TOK_EQ || op > TOK_GT)
error("invalid operands for binary operation");
- if (bt2 != t) {
- vpop(&vt, &vc);
- gen_cast(t);
- vpush();
- }
if (bt1 != t) {
vswap();
- vpop(&vt, &vc);
gen_cast(t);
- vpush();
vswap();
}
+ if (bt2 != t) {
+ gen_cast(t);
+ }
gen_opf(op);
if (op >= TOK_EQ && op <= TOK_GT) {
/* the result is an int */
- vt = (vt & ~VT_TYPE) | VT_INT;
+ vtop->t = (vtop->t & ~VT_TYPE) | VT_INT;
} else {
- vt = (vt & ~VT_TYPE) | t;
+ vtop->t = (vtop->t & ~VT_TYPE) | t;
}
- } else if (op == '+' | op == '-') {
+ } else if (op == '+' || op == '-') {
if ((t1 & VT_BTYPE) == VT_PTR &&
(t2 & VT_BTYPE) == VT_PTR) {
if (op != '-')
@@ -2180,24 +2173,22 @@ void gen_op(int op)
/* XXX: check that types are compatible */
u = pointed_size(t1);
gen_opc(op);
- vpush();
- vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
+ /* set to integer type */
+ vtop->t = (vtop->t & ~VT_TYPE) | VT_INT;
vset(VT_CONST, u);
gen_op(TOK_PDIV);
} else if ((t1 & VT_BTYPE) == VT_PTR ||
(t2 & VT_BTYPE) == VT_PTR) {
if ((t2 & VT_BTYPE) == VT_PTR) {
- swap(vstack_ptr - 4, vstack_ptr - 2);
- swap(vstack_ptr - 3, vstack_ptr - 1);
+ vswap();
swap(&t1, &t2);
}
/* stack-4 contains pointer, stack-2 value to add */
- vset(VT_CONST, pointed_size(vstack_ptr[-4]));
+ vset(VT_CONST, pointed_size(vtop[-1].t));
gen_op('*');
- vpush();
gen_opc(op);
/* put again type if gen_opc() swaped operands */
- vt = (vt & ~VT_TYPE) | (t1 & VT_TYPE);
+ vtop->t = (vtop->t & ~VT_TYPE) | (t1 & VT_TYPE);
} else {
gen_opc(op);
}
@@ -2225,23 +2216,22 @@ void gen_op(int op)
}
}
-/* cast (vt, vc) to 't' type */
+/* cast 'vtop' to 't' type */
void gen_cast(int t)
{
int r, bits, bt, vbt;
- r = vt & VT_VALMASK;
+ r = vtop->t & VT_VALMASK;
if (!(t & VT_LVAL)) {
/* if not lvalue, then we convert now */
bt = t & VT_BTYPE;
- vbt = vt & VT_BTYPE;
+ vbt = vtop->t & VT_BTYPE;
if (bt != vbt) {
if (is_float(bt)) {
/* need to generate value and do explicit cast */
gv();
gen_cvtf(bt);
} else if (bt == VT_BOOL) {
- vpush();
vset(VT_CONST, 0);
gen_op(TOK_NE);
} else if (bt == VT_BYTE || bt == VT_SHORT) {
@@ -2249,7 +2239,6 @@ void gen_cast(int t)
bits = 8;
else
bits = 16;
- vpush();
if (t & VT_UNSIGNED) {
vset(VT_CONST, (1 << bits) - 1);
gen_op('&');
@@ -2257,14 +2246,13 @@ void gen_cast(int t)
bits = 32 - bits;
vset(VT_CONST, bits);
gen_op(TOK_SHL);
- vpush();
- vset(VT_CONST, bits);
- gen_op(TOK_SAR);
+ vset(VT_CONST, bits);
+ gen_op(TOK_SAR);
}
}
}
}
- vt = (vt & ~VT_TYPE) | t;
+ vtop->t = (vtop->t & ~VT_TYPE) | t;
}
/* return type size. Put alignment at 'a' */
@@ -2290,7 +2278,7 @@ int type_size(int t, int *a)
} else if (bt == VT_LDOUBLE) {
*a = LDOUBLE_ALIGN;
return LDOUBLE_SIZE;
- } else if (bt == VT_DOUBLE || vt == VT_LLONG) {
+ } else if (bt == VT_DOUBLE || bt == VT_LLONG) {
*a = 8;
return 8;
} else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) {
@@ -2322,60 +2310,54 @@ int mk_pointer(int t)
return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & ~VT_TYPE);
}
-/* store value in lvalue pushed on stack */
+/* store vtop in lvalue pushed on stack */
void vstore(void)
{
int ft, fc, r, t, size, align, bit_size, bit_pos;
GFuncContext gf;
- if ((vt & VT_BTYPE) == VT_STRUCT) {
+ ft = vtop[-1].t;
+ if ((vtop->t & VT_BTYPE) == VT_STRUCT) {
/* if structure, only generate pointer */
/* structure assignment : generate memcpy */
/* XXX: optimize if small size */
+ vdup();
gfunc_start(&gf);
/* type size */
- ft = vt;
- fc = vc;
- size = type_size(vt, &align);
+ size = type_size(vtop->t, &align);
vset(VT_CONST, size);
gfunc_param(&gf);
/* source */
- vt = ft & ~VT_LVAL;
- vc = fc;
+ vtop->t &= ~VT_LVAL;
gfunc_param(&gf);
/* destination */
- vpop(&vt, &vc);
- vt &= ~VT_LVAL;
+ vswap();
+ vtop->t &= ~VT_LVAL;
gfunc_param(&gf);
save_regs();
vset(VT_CONST, (int)&memcpy);
gfunc_call(&gf);
-
- /* generate again current type */
- vt = ft;
- vc = fc;
- } else if (vstack_ptr[-2] & VT_BITFIELD) {
+ /* leave source on stack */
+ } else if (ft & VT_BITFIELD) {
/* bitfield store handling */
- ft = vstack_ptr[-2];
bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f;
bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
/* remove bit field info to avoid loops */
- vstack_ptr[-2] = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
+ vtop[-1].t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
+
+ /* duplicate destination */
+ vdup();
+ vtop[-1] = vtop[-2];
/* mask and shift source */
- vpush();
vset(VT_CONST, (1 << bit_size) - 1);
gen_op('&');
- vpush();
vset(VT_CONST, bit_pos);
gen_op(TOK_SHL);
- vpush();
/* load destination, mask and or with source */
- vt = vstack_ptr[-4];
- vc = vstack_ptr[-3];
- vpush();
+ vswap();
vset(VT_CONST, ~(((1 << bit_size) - 1) << bit_pos));
gen_op('&');
gen_op('|');
@@ -2383,13 +2365,12 @@ void vstore(void)
vstore();
} else {
/* generate cast if needed implicit cast for bool */
- if ((vstack_ptr[-2] & VT_BTYPE) == VT_BOOL) {
+ if ((ft & VT_BTYPE) == VT_BOOL) {
gen_cast(VT_BOOL);
}
r = gv(); /* generate value */
- vpush();
- ft = vstack_ptr[-4];
- fc = vstack_ptr[-3];
+ ft = vtop[-1].t;
+ fc = vtop[-1].c;
/* if lvalue was saved on stack, must read it */
if ((ft & VT_VALMASK) == VT_LLOCAL) {
t = get_reg(REG_CLASS_INT);
@@ -2397,7 +2378,9 @@ void vstore(void)
ft = (ft & ~VT_VALMASK) | t;
}
store(r, ft, fc);
- vstack_ptr -= 4;
+ vtop--;
+ vtop->t = (ft & VT_TYPE) | r;
+ vtop->c = 0;
}
}
@@ -2405,26 +2388,27 @@ void vstore(void)
void inc(int post, int c)
{
int r, r1;
+
test_lvalue();
if (post)
- vpush(); /* room for returned value */
- vpush(); /* save lvalue */
+ vdup(); /* room for returned value */
+ vdup(); /* save lvalue */
r = gv();
- vpush(); /* save value */
if (post) {
/* duplicate value */
/* XXX: handle floats */
r1 = get_reg(REG_CLASS_INT);
load(r1, r, 0); /* move r to r1 */
- vstack_ptr[-6] = (vt & VT_TYPE) | r1;
- vstack_ptr[-5] = 0;
+ /* duplicates value */
+ vtop[-2].t = (vtop->t & VT_TYPE) | r1;
+ vtop[-2].c = 0;
}
/* add constant */
vset(VT_CONST, c - TOK_MID);
gen_op('+');
vstore(); /* store value */
if (post)
- vpop(&vt, &vc);
+ vpop(); /* if post op, return saved value */
}
/* enum/struct/union declaration */
@@ -2770,7 +2754,7 @@ int post_type(int t)
}
/* Read a type declaration (except basic type), and return the
- type. If v is true, then also put variable name in 'vc' */
+ type. If v is true, then also put variable name in 'vtop->c' */
int type_decl(int *v, int t, int td)
{
int u, p;
@@ -2833,13 +2817,13 @@ Sym *external_sym(int v, int u)
void indir(void)
{
- if (vt & VT_LVAL)
+ if (vtop->t & VT_LVAL)
gv();
- if ((vt & VT_BTYPE) != VT_PTR)
+ if ((vtop->t & VT_BTYPE) != VT_PTR)
expect("pointer");
- vt = pointed_type(vt);
- if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
- vt |= VT_LVAL;
+ vtop->t = pointed_type(vtop->t);
+ if (!(vtop->t & VT_ARRAY)) /* an array is never an lvalue */
+ vtop->t |= VT_LVAL;
}
void unary(void)
@@ -2923,22 +2907,21 @@ void unary(void)
except for unary '&' and sizeof. Since we consider that
functions are not lvalues, we only have to handle it
there and in function calls. */
- if ((vt & VT_BTYPE) != VT_FUNC)
+ if ((vtop->t & VT_BTYPE) != VT_FUNC)
test_lvalue();
- vt = mk_pointer(vt & VT_LVALN);
+ vtop->t = mk_pointer(vtop->t & VT_LVALN);
} else
if (t == '!') {
unary();
- if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST)
- vc = !vc;
- else if ((vt & VT_VALMASK) == VT_CMP)
- vc = vc ^ 1;
+ if ((vtop->t & (VT_VALMASK | VT_LVAL)) == VT_CONST)
+ vtop->c = !vtop->c;
+ else if ((vtop->t & VT_VALMASK) == VT_CMP)
+ vtop->c = vtop->c ^ 1;
else
vset(VT_JMP, gtst(1, 0));
} else
if (t == '~') {
unary();
- vpush();
vset(VT_CONST, -1);
gen_op('^');
} else
@@ -2946,25 +2929,30 @@ void unary(void)
unary();
} else
if (t == TOK_SIZEOF) {
- /* XXX: some code can be generated */
if (tok == '(') {
next();
if (t = ist())
- vt = type_decl(&n, t, TYPE_ABSTRACT);
- else
+ t = type_decl(&n, t, TYPE_ABSTRACT);
+ else {
+ /* XXX: some code could be generated: add eval
+ flag */
expr();
+ t = vtop->t;
+ vpop();
+ }
skip(')');
} else {
unary();
+ t = vtop->t;
+ vpop();
}
- vset(VT_CONST, type_size(vt, &t));
+ vset(VT_CONST, type_size(t, &t));
} else
- if (t == TOK_INC | t == TOK_DEC) {
+ if (t == TOK_INC || t == TOK_DEC) {
unary();
inc(0, t);
} else if (t == '-') {
vset(VT_CONST, 0);
- vpush();
unary();
gen_op('-');
} else
@@ -2982,8 +2970,8 @@ void unary(void)
}
vset(s->t, s->c);
/* if forward reference, we must point to s */
- if (vt & VT_FORWARD)
- vc = (int)s;
+ if (vtop->t & VT_FORWARD)
+ vtop->c = (int)s;
}
}
@@ -2997,12 +2985,12 @@ void unary(void)
if (tok == TOK_ARROW)
indir();
test_lvalue();
- vt &= VT_LVALN;
+ vtop->t &= VT_LVALN;
next();
/* expect pointer on structure */
- if ((vt & VT_BTYPE) != VT_STRUCT)
+ if ((vtop->t & VT_BTYPE) != VT_STRUCT)
expect("struct or union");
- s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
+ s = sym_find(((unsigned)vtop->t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
/* find field */
tok |= SYM_FIELD;
while (s = s->next) {
@@ -3012,19 +3000,17 @@ void unary(void)
if (!s)
error("field not found");
/* add field offset to pointer */
- vt = (vt & ~VT_TYPE) | VT_INT; /* change type to int */
- vpush();
+ vtop->t = (vtop->t & ~VT_TYPE) | VT_INT; /* change type to int */
vset(VT_CONST, s->c);
gen_op('+');
/* change type to field type, and set to lvalue */
- vt = (vt & ~VT_TYPE) | s->t;
+ vtop->t = (vtop->t & ~VT_TYPE) | s->t;
/* an array is never an lvalue */
- if (!(vt & VT_ARRAY))
- vt |= VT_LVAL;
+ if (!(vtop->t & VT_ARRAY))
+ vtop->t |= VT_LVAL;
next();
} else if (tok == '[') {
next();
- vpush();
expr();
gen_op('+');
indir();
@@ -3033,23 +3019,22 @@ void unary(void)
int rett, retc;
/* function call */
- if ((vt & VT_BTYPE) != VT_FUNC) {
+ if ((vtop->t & VT_BTYPE) != VT_FUNC) {
/* pointer test (no array accepted) */
- if ((vt & (VT_BTYPE | VT_ARRAY)) == VT_PTR) {
- vt = pointed_type(vt);
- if ((vt & VT_BTYPE) != VT_FUNC)
+ if ((vtop->t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) {
+ vtop->t = pointed_type(vtop->t);
+ if ((vtop->t & VT_BTYPE) != VT_FUNC)
goto error_func;
} else {
error_func:
expect("function pointer");
}
} else {
- vt &= ~VT_LVAL; /* no lvalue */
+ vtop->t &= ~VT_LVAL; /* no lvalue */
}
/* get return type */
- s = sym_find((unsigned)vt >> VT_STRUCT_SHIFT);
- vpush(); /* push function address */
+ s = sym_find((unsigned)vtop->t >> VT_STRUCT_SHIFT);
save_regs(); /* save used temporary registers */
gfunc_start(&gf);
next();
@@ -3112,7 +3097,7 @@ void unary(void)
/* pass it as 'int' to avoid structure arg passing
problems */
vset(VT_INT | VT_LOCAL, loc);
- retc = vc;
+ retc = vtop->c;
gfunc_param(&gf);
} else {
rett = s->t | FUNC_RET_REG; /* return in register */
@@ -3127,11 +3112,9 @@ void unary(void)
}
#endif
skip(')');
- vpop(&vt, &vc);
gfunc_call(&gf);
/* return value */
- vt = rett;
- vc = retc;
+ vset(rett, retc);
} else {
break;
}
@@ -3215,15 +3198,14 @@ void uneq(void)
tok == TOK_A_XOR || tok == TOK_A_OR ||
tok == TOK_A_SHL || tok == TOK_A_SAR) {
test_lvalue();
- vpush();
t = tok;
next();
if (t == '=') {
expr_eq();
- if (!check_assign_types(vstack_ptr[-2], vt))
+ if (!check_assign_types(vtop[-1].t, vtop[0].t))
warning("incompatible types");
} else {
- vpush();
+ vdup();
expr_eq();
gen_op(t & 0x7f);
}
@@ -3250,7 +3232,6 @@ void sum(int l)
(l == 7 & tok == '|') |
(l == 8 & tok == TOK_LAND) |
(l == 9 & tok == TOK_LOR)) {
- vpush();
t = tok;
next();
sum(l);
@@ -3308,29 +3289,34 @@ void expr_eq(void)
if (const_wanted) {
sum(10);
if (tok == '?') {
- c = vc;
+ c = vtop->c;
+ vpop();
next();
expr();
- t = vc;
+ t = vtop->c;
+ vpop();
skip(':');
expr_eq();
if (c)
- vc = t;
+ vtop->c = t;
}
} else {
eor();
if (tok == '?') {
next();
t = gtst(1, 0);
+
expr();
r1 = gv();
+ vpop();
skip(':');
u = gjmp(0);
+
gsym(t);
expr_eq();
r2 = gv();
move_reg(r1, r2);
- vt = (vt & VT_TYPE) | r1;
+ vtop->t = (vtop->t & VT_TYPE) | r1;
gsym(u);
}
}
@@ -3342,20 +3328,23 @@ void expr(void)
expr_eq();
if (tok != ',')
break;
+ vpop();
next();
}
}
int expr_const(void)
{
- int a;
+ int a, c;
a = const_wanted;
const_wanted = 1;
expr_eq();
- if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
+ if ((vtop->t & (VT_CONST | VT_LVAL)) != VT_CONST)
expect("constant");
const_wanted = a;
- return vc;
+ c = vtop->c;
+ vpop();
+ return c;
}
/* return the label token if current token is a label, otherwise
@@ -3434,21 +3423,20 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
} else if (tok == TOK_RETURN) {
next();
if (tok != ';') {
+ expr();
if ((func_vt & VT_BTYPE) == VT_STRUCT) {
/* if returning structure, must copy it to implicit
first pointer arg location */
vset(mk_pointer(func_vt) | VT_LOCAL | VT_LVAL, func_vc);
indir();
- vpush();
- }
- expr();
- if ((func_vt & VT_BTYPE) == VT_STRUCT) {
+ vswap();
/* copy structure value to pointer */
vstore();
} else {
/* move return value to standard return register */
move_reg(FUNC_RET_REG, gv());
}
+ vpop();
}
skip(';');
rsym = gjmp(rsym); /* jmp */
@@ -3470,8 +3458,10 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
int e;
next();
skip('(');
- if (tok != ';')
+ if (tok != ';') {
expr();
+ vpop();
+ }
skip(';');
d = ind;
c = ind;
@@ -3486,6 +3476,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
e = gjmp(0);
c = ind;
expr();
+ vpop();
oad(0xe9, d - ind - 5); /* jmp */
gsym(e);
}
@@ -3516,6 +3507,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
skip('(');
expr();
case_reg = gv();
+ vpop();
skip(')');
a = 0;
b = gjmp(0); /* jump to first case */
@@ -3538,7 +3530,6 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
b = gjmp(0);
gsym(*case_sym);
vset(case_reg, 0);
- vpush();
vset(VT_CONST, a);
gen_op(TOK_EQ);
*case_sym = gtst(1, 0);
@@ -3592,6 +3583,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
/* expression case */
if (tok != ';') {
expr();
+ vpop();
}
skip(';');
}
@@ -3695,14 +3687,13 @@ void init_putv(int t, int c, int v, int is_expr)
else
*(int *)c = v;
} else {
- vt = t;
- vc = c;
- vpush();
+ vset(t, c);
if (is_expr)
expr_eq();
else
vset(VT_CONST, v);
vstore();
+ vpop();
}
}
@@ -4152,7 +4143,7 @@ int tcc_compile_file(const char *filename1)
include_stack_ptr = include_stack;
ifdef_stack_ptr = ifdef_stack;
- vstack_ptr = vstack;
+ vtop = vstack - 1;
anon_sym = SYM_FIRST_ANOM;
define_start = define_stack.top;