finished bound check code (still slow) - fixed binary ops code gen - fixed float return
This commit is contained in:
parent
ad28d4c5b0
commit
5f85585b77
1 changed files with 97 additions and 21 deletions
118
tcc.c
118
tcc.c
|
|
@ -163,7 +163,9 @@ int section_num;
|
||||||
Section *text_section, *data_section, *bss_section; /* predefined sections */
|
Section *text_section, *data_section, *bss_section; /* predefined sections */
|
||||||
Section *cur_text_section; /* current section where function code is
|
Section *cur_text_section; /* current section where function code is
|
||||||
generated */
|
generated */
|
||||||
|
/* bound check related sections */
|
||||||
Section *bounds_section; /* contains global data bound description */
|
Section *bounds_section; /* contains global data bound description */
|
||||||
|
Section *lbounds_section; /* contains local data bound description */
|
||||||
/* debug sections */
|
/* debug sections */
|
||||||
Section *stab_section, *stabstr_section, *symtab_section, *strtab_section;
|
Section *stab_section, *stabstr_section, *symtab_section, *strtab_section;
|
||||||
|
|
||||||
|
|
@ -209,18 +211,20 @@ int gnu_ext = 1;
|
||||||
int tcc_ext = 1;
|
int tcc_ext = 1;
|
||||||
|
|
||||||
/* The current value can be: */
|
/* The current value can be: */
|
||||||
#define VT_VALMASK 0x00ff
|
#define VT_VALMASK 0x00ff
|
||||||
#define VT_CONST 0x00f0 /* constant in vc
|
#define VT_CONST 0x00f0 /* constant in vc
|
||||||
(must be first non register value) */
|
(must be first non register value) */
|
||||||
#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */
|
#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */
|
||||||
#define VT_LOCAL 0x00f2 /* offset on stack */
|
#define VT_LOCAL 0x00f2 /* offset on stack */
|
||||||
#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */
|
#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */
|
||||||
#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */
|
#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */
|
||||||
#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */
|
#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */
|
||||||
#define VT_LVAL 0x0100 /* var is an lvalue */
|
#define VT_LVAL 0x0100 /* var is an lvalue */
|
||||||
#define VT_FORWARD 0x0200 /* value is forward reference */
|
#define VT_FORWARD 0x0200 /* value is forward reference */
|
||||||
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
|
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
|
||||||
char/short stored in integer registers) */
|
char/short stored in integer registers) */
|
||||||
|
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
|
||||||
|
dereferencing value */
|
||||||
|
|
||||||
/* types */
|
/* types */
|
||||||
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
|
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
|
||||||
|
|
@ -402,6 +406,7 @@ void decl(int l);
|
||||||
void decl_initializer(int t, int r, int c, int first, int size_only);
|
void decl_initializer(int t, int r, int c, int first, int size_only);
|
||||||
int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init);
|
int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init);
|
||||||
int gv(int rc);
|
int gv(int rc);
|
||||||
|
void gv2(int rc1, int rc2);
|
||||||
void move_reg(int r, int s);
|
void move_reg(int r, int s);
|
||||||
void save_regs(void);
|
void save_regs(void);
|
||||||
void save_reg(int r);
|
void save_reg(int r);
|
||||||
|
|
@ -2339,6 +2344,20 @@ void gaddrof(void)
|
||||||
vtop->r = (vtop->r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
|
vtop->r = (vtop->r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* generate lvalue bound code */
|
||||||
|
void gbound(void)
|
||||||
|
{
|
||||||
|
vtop->r &= ~VT_MUSTBOUND;
|
||||||
|
/* if lvalue, then use checking code before dereferencing */
|
||||||
|
if (vtop->r & VT_LVAL) {
|
||||||
|
gaddrof();
|
||||||
|
vpushi(0);
|
||||||
|
gen_bounded_ptr_add1();
|
||||||
|
gen_bounded_ptr_add2(1);
|
||||||
|
vtop->r |= VT_LVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* store vtop a register belonging to class 'rc'. lvalues are
|
/* store vtop a register belonging to class 'rc'. lvalues are
|
||||||
converted to values. Cannot be used if cannot be converted to
|
converted to values. Cannot be used if cannot be converted to
|
||||||
register value (such as structures). */
|
register value (such as structures). */
|
||||||
|
|
@ -2377,6 +2396,9 @@ int gv(int rc)
|
||||||
data_offset += size << 2;
|
data_offset += size << 2;
|
||||||
data_section->data_ptr = (unsigned char *)data_offset;
|
data_section->data_ptr = (unsigned char *)data_offset;
|
||||||
}
|
}
|
||||||
|
if (vtop->r & VT_MUSTBOUND)
|
||||||
|
gbound();
|
||||||
|
|
||||||
r = vtop->r & VT_VALMASK;
|
r = vtop->r & VT_VALMASK;
|
||||||
/* need to reload if:
|
/* need to reload if:
|
||||||
- constant
|
- constant
|
||||||
|
|
@ -2436,6 +2458,33 @@ int gv(int rc)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */
|
||||||
|
void gv2(int rc1, int rc2)
|
||||||
|
{
|
||||||
|
/* generate more generic register first */
|
||||||
|
if (rc1 <= rc2) {
|
||||||
|
vswap();
|
||||||
|
gv(rc1);
|
||||||
|
vswap();
|
||||||
|
gv(rc2);
|
||||||
|
/* test if reload is needed for first register */
|
||||||
|
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||||
|
vswap();
|
||||||
|
gv(rc1);
|
||||||
|
vswap();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gv(rc2);
|
||||||
|
vswap();
|
||||||
|
gv(rc1);
|
||||||
|
vswap();
|
||||||
|
/* test if reload is needed for first register */
|
||||||
|
if ((vtop[0].r & VT_VALMASK) >= VT_CONST) {
|
||||||
|
gv(rc2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* expand long long on stack in two int registers */
|
/* expand long long on stack in two int registers */
|
||||||
void lexpand(void)
|
void lexpand(void)
|
||||||
{
|
{
|
||||||
|
|
@ -2454,10 +2503,7 @@ void lexpand(void)
|
||||||
/* build a long long from two ints */
|
/* build a long long from two ints */
|
||||||
void lbuild(int t)
|
void lbuild(int t)
|
||||||
{
|
{
|
||||||
vswap();
|
gv2(RC_INT, RC_INT);
|
||||||
gv(RC_INT);
|
|
||||||
vswap();
|
|
||||||
gv(RC_INT);
|
|
||||||
vtop[-1].r2 = vtop[0].r;
|
vtop[-1].r2 = vtop[0].r;
|
||||||
vtop[-1].t = t;
|
vtop[-1].t = t;
|
||||||
vpop();
|
vpop();
|
||||||
|
|
@ -2890,13 +2936,15 @@ void gen_op(int op)
|
||||||
vpushi(pointed_size(vtop[-1].t));
|
vpushi(pointed_size(vtop[-1].t));
|
||||||
gen_op('*');
|
gen_op('*');
|
||||||
if (do_bounds_check) {
|
if (do_bounds_check) {
|
||||||
/* if bounded pointers, we generate a special code to test bounds */
|
/* if bounded pointers, we generate a special code to
|
||||||
|
test bounds */
|
||||||
if (op == '-') {
|
if (op == '-') {
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vswap();
|
vswap();
|
||||||
gen_op('-');
|
gen_op('-');
|
||||||
}
|
}
|
||||||
gen_bounded_ptr_add();
|
gen_bounded_ptr_add1();
|
||||||
|
gen_bounded_ptr_add2(0);
|
||||||
} else {
|
} else {
|
||||||
gen_opc(op);
|
gen_opc(op);
|
||||||
}
|
}
|
||||||
|
|
@ -3503,10 +3551,16 @@ void vstore(void)
|
||||||
/* store result */
|
/* store result */
|
||||||
vstore();
|
vstore();
|
||||||
} else {
|
} else {
|
||||||
|
/* bound check case */
|
||||||
|
if (vtop[-1].r & VT_MUSTBOUND) {
|
||||||
|
vswap();
|
||||||
|
gbound();
|
||||||
|
vswap();
|
||||||
|
}
|
||||||
rc = RC_INT;
|
rc = RC_INT;
|
||||||
if (is_float(ft))
|
if (is_float(ft))
|
||||||
rc = RC_FLOAT;
|
rc = RC_FLOAT;
|
||||||
r = gv(rc); /* generate value (XXX: move that to store code) */
|
r = gv(rc); /* generate value */
|
||||||
/* if lvalue was saved on stack, must read it */
|
/* if lvalue was saved on stack, must read it */
|
||||||
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
|
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
|
||||||
SValue sv;
|
SValue sv;
|
||||||
|
|
@ -4043,8 +4097,13 @@ void indir(void)
|
||||||
if (vtop->r & VT_LVAL)
|
if (vtop->r & VT_LVAL)
|
||||||
gv(RC_INT);
|
gv(RC_INT);
|
||||||
vtop->t = pointed_type(vtop->t);
|
vtop->t = pointed_type(vtop->t);
|
||||||
if (!(vtop->t & VT_ARRAY)) /* an array is never an lvalue */
|
/* an array is never an lvalue */
|
||||||
|
if (!(vtop->t & VT_ARRAY)) {
|
||||||
vtop->r |= VT_LVAL;
|
vtop->r |= VT_LVAL;
|
||||||
|
/* if bound checking, the referenced pointer must be checked */
|
||||||
|
if (do_bounds_check)
|
||||||
|
vtop->r |= VT_MUSTBOUND;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pass a parameter to a function and do type checking and casting */
|
/* pass a parameter to a function and do type checking and casting */
|
||||||
|
|
@ -4659,7 +4718,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
|
||||||
} else {
|
} else {
|
||||||
gv(RC_IRET);
|
gv(RC_IRET);
|
||||||
}
|
}
|
||||||
vpop();
|
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
|
||||||
}
|
}
|
||||||
skip(';');
|
skip(';');
|
||||||
rsym = gjmp(rsym); /* jmp */
|
rsym = gjmp(rsym); /* jmp */
|
||||||
|
|
@ -5195,8 +5254,23 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
||||||
if (ad->aligned > align)
|
if (ad->aligned > align)
|
||||||
align = ad->aligned;
|
align = ad->aligned;
|
||||||
if ((r & VT_VALMASK) == VT_LOCAL) {
|
if ((r & VT_VALMASK) == VT_LOCAL) {
|
||||||
|
if (do_bounds_check && (t & VT_ARRAY))
|
||||||
|
loc--;
|
||||||
loc = (loc - size) & -align;
|
loc = (loc - size) & -align;
|
||||||
addr = loc;
|
addr = loc;
|
||||||
|
/* handles bounds */
|
||||||
|
/* XXX: currently, since we do only one pass, we cannot track
|
||||||
|
'&' operators, so we add only arrays */
|
||||||
|
if (do_bounds_check && (t & VT_ARRAY)) {
|
||||||
|
int *bounds_ptr;
|
||||||
|
/* add padding between regions */
|
||||||
|
loc--;
|
||||||
|
/* then add local bound info */
|
||||||
|
bounds_ptr = (int *)lbounds_section->data_ptr;
|
||||||
|
*bounds_ptr++ = addr;
|
||||||
|
*bounds_ptr++ = size;
|
||||||
|
lbounds_section->data_ptr = (unsigned char *)bounds_ptr;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* compute section */
|
/* compute section */
|
||||||
sec = ad->section;
|
sec = ad->section;
|
||||||
|
|
@ -5219,7 +5293,7 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
||||||
int *bounds_ptr;
|
int *bounds_ptr;
|
||||||
/* first, we need to add at least one byte between each region */
|
/* first, we need to add at least one byte between each region */
|
||||||
data_offset++;
|
data_offset++;
|
||||||
/* then add global data info */
|
/* then add global bound info */
|
||||||
bounds_ptr = (int *)bounds_section->data_ptr;
|
bounds_ptr = (int *)bounds_section->data_ptr;
|
||||||
*bounds_ptr++ = addr;
|
*bounds_ptr++ = addr;
|
||||||
*bounds_ptr++ = size;
|
*bounds_ptr++ = size;
|
||||||
|
|
@ -6059,9 +6133,11 @@ int main(int argc, char **argv)
|
||||||
} else if (r[1] == 'b') {
|
} else if (r[1] == 'b') {
|
||||||
if (!do_bounds_check) {
|
if (!do_bounds_check) {
|
||||||
do_bounds_check = 1;
|
do_bounds_check = 1;
|
||||||
/* create bounds section for global data */
|
/* create bounds sections */
|
||||||
bounds_section = new_section(".bounds",
|
bounds_section = new_section(".bounds",
|
||||||
SHT_PROGBITS, SHF_ALLOC);
|
SHT_PROGBITS, SHF_ALLOC);
|
||||||
|
lbounds_section = new_section(".lbounds",
|
||||||
|
SHT_PROGBITS, SHF_ALLOC);
|
||||||
/* debug is implied */
|
/* debug is implied */
|
||||||
goto debug_opt;
|
goto debug_opt;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue