tccgen: nocode_wanted alternatively

tccgen.c: remove any 'nocode_wanted' checks, except in
- greloca(), disables output elf symbols and relocs
- get_reg(), will return just the first suitable reg)
- save_regs(), will do nothing

Some minor adjustments were made where nocode_wanted is set.

xxx-gen.c: disable code output directly where it happens
in functions:
- g(), output disabled
- gjmp(), will do nothing
- gtst(), dto.
This commit is contained in:
grischka 2016-12-18 17:23:33 +01:00
parent 77d7ea04ac
commit f843cadb6b
7 changed files with 111 additions and 131 deletions

View File

@ -214,7 +214,8 @@ void o(uint32_t i)
{
/* this is a good place to start adding big-endian support*/
int ind1;
if (nocode_wanted)
return;
ind1 = ind + 4;
if (!cur_text_section)
tcc_error("compiler error! This happens f.ex. if the compiler\n"
@ -1411,6 +1412,8 @@ void gfunc_epilog(void)
int gjmp(int t)
{
int r;
if (nocode_wanted)
return t;
r=ind;
o(0xE0000000|encbranch(r,t,1));
return r;
@ -1427,9 +1430,13 @@ int gtst(int inv, int t)
{
int v, r;
uint32_t op;
v = vtop->r & VT_VALMASK;
r=ind;
if (v == VT_CMP) {
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
op|=encbranch(r,t,1);
o(op);

View File

@ -95,6 +95,8 @@ static uint32_t fltr(int r)
ST_FUNC void o(unsigned int c)
{
int ind1 = ind + 4;
if (nocode_wanted)
return;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
write32le(cur_text_section->data + ind, c);
@ -1278,6 +1280,8 @@ ST_FUNC void gfunc_epilog(void)
ST_FUNC int gjmp(int t)
{
int r = ind;
if (nocode_wanted)
return t;
o(t);
return r;
}

View File

@ -182,7 +182,8 @@ FILE *f = NULL;
void C67_g(int c)
{
int ind1;
if (nocode_wanted)
return;
#ifdef ASSEMBLY_LISTING_C67
fprintf(f, " %08X", c);
#endif
@ -2038,6 +2039,8 @@ void gfunc_epilog(void)
int gjmp(int t)
{
int ind1 = ind;
if (nocode_wanted)
return t;
C67_MVKL(C67_A0, t); //r=reg to load, constant
C67_MVKH(C67_A0, t); //r=reg to load, constant
@ -2070,7 +2073,9 @@ int gtst(int inv, int t)
int v, *p;
v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
// C67 uses B2 sort of as flags register
ind1 = ind;

View File

@ -70,8 +70,8 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
#define psym oad
/* generate jmp to a label */
#define gjmp2(instr,lbl) oad(instr,lbl)
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
@ -100,6 +100,8 @@ static unsigned long func_bound_ind;
ST_FUNC void g(int c)
{
int ind1;
if (nocode_wanted)
return;
ind1 = ind + 1;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
@ -145,23 +147,16 @@ ST_FUNC void gsym(int t)
gsym_addr(t, ind);
}
/* psym is used to put an instruction with a data field which is a
reference to a symbol. It is in fact the same as oad ! */
#define psym oad
/* instruction + 4 bytes data. Return the address of the data */
ST_FUNC int oad(int c, int s)
{
int ind1;
int t;
if (nocode_wanted)
return s;
o(c);
ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
write32le(cur_text_section->data + ind, s);
s = ind;
ind = ind1;
return s;
t = ind;
gen_le32(s);
return t;
}
/* output constant with relocation if 'r & VT_SYM' is true */
@ -676,7 +671,7 @@ ST_FUNC void gfunc_epilog(void)
/* generate a jump to a label */
ST_FUNC int gjmp(int t)
{
return psym(0xe9, t);
return gjmp2(0xe9, t);
}
/* generate a jump to a fixed address */
@ -722,10 +717,12 @@ ST_FUNC void gtst_addr(int inv, int a)
ST_FUNC int gtst(int inv, int t)
{
int v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
g(0x0f);
t = psym((vtop->c.i - 16) ^ inv, t);
t = gjmp2((vtop->c.i - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {

View File

@ -915,8 +915,12 @@ static void asm_parse_directive(TCCState *s1)
/* assemble a file */
static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
{
int saved_nocode_wanted;
int opcode;
saved_nocode_wanted = nocode_wanted;
nocode_wanted = 0;
/* XXX: undefine C labels */
ch = file->buf_ptr[0];
@ -960,7 +964,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
/* handle "extern void vide(void); __asm__("vide: ret");" as
"__asm__("globl vide\nvide: ret");" */
Sym *sym = sym_find(opcode);
if (sym && (sym->type.t & VT_EXTERN) && nocode_wanted) {
if (sym && (sym->type.t & VT_EXTERN) && saved_nocode_wanted) {
sym = label_find(opcode);
if (!sym) {
sym = label_push(&s1->asm_labels, opcode, 0);
@ -989,6 +993,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
asm_free_labels(s1);
nocode_wanted = saved_nocode_wanted;
return 0;
}

144
tccgen.c
View File

@ -69,6 +69,7 @@ ST_DATA struct switch_t {
} *cur_switch; /* current switch */
/* ------------------------------------------------------------------------- */
static void gen_cast(CType *type);
static inline CType *pointed_type(CType *type);
static int is_compatible_types(CType *type1, CType *type2);
@ -322,11 +323,16 @@ ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type,
addr_t addend)
{
int c = 0;
if (nocode_wanted && s == cur_text_section)
return;
if (sym) {
if (0 == sym->c)
put_extern_sym(sym, NULL, 0, 0);
c = sym->c;
}
/* now we can add ELF relocation info */
put_elf_reloca(symtab_section, s, offset, type, c, addend);
}
@ -774,6 +780,8 @@ ST_FUNC void save_reg_upstack(int r, int n)
if ((r &= VT_VALMASK) >= VT_CONST)
return;
if (nocode_wanted)
return;
/* modify all stack values */
saved = 0;
@ -865,6 +873,8 @@ ST_FUNC int get_reg(int rc)
/* find a free register */
for(r=0;r<NB_REGS;r++) {
if (reg_classes[r] & rc) {
if (nocode_wanted)
return r;
for(p=vstack;p<=vtop;p++) {
if ((p->r & VT_VALMASK) == r ||
(p->r2 & VT_VALMASK) == r)
@ -913,7 +923,7 @@ static void move_reg(int r, int s, int t)
/* get address of vtop (vtop MUST BE an lvalue) */
ST_FUNC void gaddrof(void)
{
if (vtop->r & VT_REF && !nocode_wanted)
if (vtop->r & VT_REF)
gv(RC_INT);
vtop->r &= ~VT_LVAL;
/* tricky: if saved lvalue, then we can go back to lvalue */
@ -1317,7 +1327,7 @@ ST_FUNC void vpop(void)
v = vtop->r & VT_VALMASK;
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
/* for x86, we need to pop the FP stack */
if (v == TREG_ST0 && !nocode_wanted) {
if (v == TREG_ST0) {
o(0xd8dd); /* fstp %st(0) */
} else
#endif
@ -1607,7 +1617,7 @@ static void gen_opl(int op)
b = gvtst(0, 0);
} else {
#if defined(TCC_TARGET_I386)
b = psym(0x850f, 0);
b = gjmp2(0x850f, 0);
#elif defined(TCC_TARGET_ARM)
b = ind;
o(0x1A000000 | encbranch(ind, 0, 1));
@ -1789,23 +1799,12 @@ static void gen_opic(int op)
vtop->c.i = l2;
} else {
general_case:
if (!nocode_wanted) {
/* call low level op generator */
if (t1 == VT_LLONG || t2 == VT_LLONG ||
(PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR)))
gen_opl(op);
else
gen_opi(op);
} else {
vtop--;
/* Ensure vtop isn't marked VT_CONST in case something
up our callchain is interested in const-ness of the
expression. Also make it a non-LVAL if it was,
so that further code can't accidentally generate
a deref (happen only for buggy uses of e.g.
gv() under nocode_wanted). */
vtop->r &= ~(VT_VALMASK | VT_LVAL);
}
}
}
}
@ -1866,11 +1865,7 @@ static void gen_opif(int op)
vtop--;
} else {
general_case:
if (!nocode_wanted) {
gen_opf(op);
} else {
vtop--;
}
gen_opf(op);
}
}
@ -2149,7 +2144,7 @@ redo:
}
}
// Make sure that we have converted to an rvalue:
if (vtop->r & VT_LVAL && !nocode_wanted)
if (vtop->r & VT_LVAL)
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
}
@ -2255,7 +2250,7 @@ static void gen_cast(CType *type)
}
/* bitfields first get cast to ints */
if (vtop->type.t & VT_BITFIELD && !nocode_wanted) {
if (vtop->type.t & VT_BITFIELD) {
gv(RC_INT);
}
@ -2331,7 +2326,7 @@ static void gen_cast(CType *type)
} else if (p && dbt == VT_BOOL) {
vtop->r = VT_CONST;
vtop->c.i = 1;
} else if (!nocode_wanted) {
} else {
/* non constant case: generate code */
if (sf && df) {
/* convert from fp to fp */
@ -2883,7 +2878,6 @@ ST_FUNC void vstore(void)
/* if structure, only generate pointer */
/* structure assignment : generate memcpy */
/* XXX: optimize if small size */
if (!nocode_wanted) {
size = type_size(&vtop->type, &align);
/* destination */
@ -2910,10 +2904,7 @@ ST_FUNC void vstore(void)
/* type size */
vpushi(size);
gfunc_call(3);
} else {
vswap();
vpop();
}
/* leave source on stack */
} else if (ft & VT_BITFIELD) {
/* bitfield store handling */
@ -2961,7 +2952,6 @@ ST_FUNC void vstore(void)
vpop();
} else {
if (!nocode_wanted) {
#ifdef CONFIG_TCC_BCHECK
/* bound check case */
if (vtop[-1].r & VT_MUSTBOUND) {
@ -3020,7 +3010,7 @@ ST_FUNC void vstore(void)
} else {
store(r, vtop - 1);
}
}
vswap();
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
vtop->r |= delayed_cast;
@ -3033,10 +3023,7 @@ ST_FUNC void inc(int post, int c)
test_lvalue();
vdup(); /* save lvalue */
if (post) {
if (!nocode_wanted)
gv_dup(); /* duplicate value */
else
vdup(); /* duplicate value */
gv_dup(); /* duplicate value */
vrotb(3);
vrotb(3);
}
@ -4189,7 +4176,7 @@ ST_FUNC void indir(void)
return;
expect("pointer");
}
if ((vtop->r & VT_LVAL) && !nocode_wanted)
if (vtop->r & VT_LVAL)
gv(RC_INT);
vtop->type = *pointed_type(&vtop->type);
/* Arrays and functions are never lvalues */
@ -4382,8 +4369,7 @@ ST_FUNC void unary(void)
if (const_wanted)
tcc_error("expected constant");
/* save all registers */
if (!nocode_wanted)
save_regs(0);
save_regs(0);
/* statement expression : we do not accept break/continue
inside as GCC does */
block(NULL, NULL, 1);
@ -4610,8 +4596,6 @@ ST_FUNC void unary(void)
#ifdef TCC_TARGET_ARM64
case TOK___va_start: {
if (nocode_wanted)
tcc_error("statement in global scope");
next();
skip('(');
expr_eq();
@ -4626,8 +4610,6 @@ ST_FUNC void unary(void)
}
case TOK___va_arg: {
CType type;
if (nocode_wanted)
tcc_error("statement in global scope");
next();
skip('(');
expr_eq();
@ -4906,11 +4888,7 @@ ST_FUNC void unary(void)
if (sa)
tcc_error("too few arguments to function");
skip(')');
if (!nocode_wanted) {
gfunc_call(nb_args);
} else {
vtop -= (nb_args + 1);
}
gfunc_call(nb_args);
/* return value */
for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) {
@ -5083,9 +5061,9 @@ static void expr_land(void)
expr_or();
vpop();
}
nocode_wanted = saved_nocode_wanted;
if (t)
gsym(t);
nocode_wanted = saved_nocode_wanted;
gen_cast(&int_type);
break;
}
@ -5127,9 +5105,9 @@ static void expr_lor(void)
expr_land();
vpop();
}
nocode_wanted = saved_nocode_wanted;
if (t)
gsym(t);
nocode_wanted = saved_nocode_wanted;
gen_cast(&int_type);
break;
}
@ -5206,16 +5184,6 @@ static void expr_cond(void)
}
}
else {
/* XXX This doesn't handle nocode_wanted correctly at all.
It unconditionally calls gv/gvtst and friends. That's
the case for many of the expr_ routines. Currently
that should generate only useless code, but depending
on other operand handling this might also generate
pointer derefs for lvalue conversions whose result
is useless, but nevertheless can lead to segfault.
Somewhen we need to overhaul the whole nocode_wanted
handling. */
if (vtop != vstack) {
/* needed to avoid having different registers saved in
each branch */
@ -5575,19 +5543,22 @@ static void block(int *bsym, int *csym, int is_expr)
gexpr();
skip(')');
cond = condition_3way();
if (cond == 0)
if (cond == 1)
a = 0, vpop();
else
a = gvtst(1, 0);
if (cond == 0)
nocode_wanted |= 2;
a = gvtst(1, 0);
block(bsym, csym, 0);
if (cond != 1)
nocode_wanted = saved_nocode_wanted;
c = tok;
if (c == TOK_ELSE) {
next();
if (cond == 1)
nocode_wanted |= 2;
d = gjmp(0);
gsym(a);
if (cond == 1)
nocode_wanted |= 2;
block(bsym, csym, 0);
gsym(d); /* patch else jmp */
if (cond != 0)
@ -5610,8 +5581,7 @@ static void block(int *bsym, int *csym, int is_expr)
block(&a, &b, 0);
nocode_wanted = saved_nocode_wanted;
--local_scope;
if(!nocode_wanted)
gjmp_addr(d);
gjmp_addr(d);
gsym(a);
gsym_addr(b, d);
} else if (tok == '{') {
@ -5801,8 +5771,7 @@ static void block(int *bsym, int *csym, int is_expr)
saved_nocode_wanted = nocode_wanted;
block(&a, &b, 0);
nocode_wanted = saved_nocode_wanted;
if(!nocode_wanted)
gjmp_addr(c);
gjmp_addr(c);
gsym(a);
gsym_addr(b, c);
--local_scope;
@ -5823,11 +5792,8 @@ static void block(int *bsym, int *csym, int is_expr)
skip('(');
gsym(b);
gexpr();
if (!nocode_wanted) {
c = gvtst(0, 0);
gsym_addr(c, d);
} else
vtop--;
c = gvtst(0, 0);
gsym_addr(c, d);
nocode_wanted = saved_nocode_wanted;
skip(')');
gsym(a);
@ -5852,21 +5818,19 @@ static void block(int *bsym, int *csym, int is_expr)
a = gjmp(a); /* add implicit break */
/* case lookup */
gsym(b);
if (!nocode_wanted) {
qsort(sw.p, sw.n, sizeof(void*), case_cmp);
for (b = 1; b < sw.n; b++)
if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
tcc_error("duplicate case value");
/* Our switch table sorting is signed, so the compared
value needs to be as well when it's 64bit. */
if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
switchval.type.t &= ~VT_UNSIGNED;
vpushv(&switchval);
gcase(sw.p, sw.n, &a);
vpop();
if (sw.def_sym)
gjmp_addr(sw.def_sym);
}
qsort(sw.p, sw.n, sizeof(void*), case_cmp);
for (b = 1; b < sw.n; b++)
if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
tcc_error("duplicate case value");
/* Our switch table sorting is signed, so the compared
value needs to be as well when it's 64bit. */
if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
switchval.type.t &= ~VT_UNSIGNED;
vpushv(&switchval);
gcase(sw.p, sw.n, &a);
vpop();
if (sw.def_sym)
gjmp_addr(sw.def_sym);
dynarray_reset(&sw.p, &sw.n);
cur_switch = saved;
/* break label */
@ -5910,10 +5874,7 @@ static void block(int *bsym, int *csym, int is_expr)
gexpr();
if ((vtop->type.t & VT_BTYPE) != VT_PTR)
expect("pointer");
if (!nocode_wanted)
ggoto();
else
vtop--;
ggoto();
} else if (tok >= TOK_UIDENT) {
s = label_find(tok);
/* put forward definition if needed */
@ -5924,9 +5885,7 @@ static void block(int *bsym, int *csym, int is_expr)
s->r = LABEL_FORWARD;
}
vla_sp_restore_root();
if (nocode_wanted)
;
else if (s->r & LABEL_FORWARD)
if (s->r & LABEL_FORWARD)
s->jnext = gjmp(s->jnext);
else
gjmp_addr(s->jnext);
@ -6893,6 +6852,7 @@ static void gen_function(Sym *sym)
rsym = 0;
block(NULL, NULL, 0);
nocode_wanted = 0;
gsym(rsym);
gfunc_epilog();
cur_text_section->data_offset = ind;

View File

@ -145,6 +145,8 @@ static int func_ret_sub;
ST_FUNC void g(int c)
{
int ind1;
if (nocode_wanted)
return;
ind1 = ind + 1;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
@ -213,9 +215,6 @@ void gsym(int t)
gsym_addr(t, ind);
}
/* psym is used to put an instruction with a data field which is a
reference to a symbol. It is in fact the same as oad ! */
#define psym oad
static int is64_type(int t)
{
@ -227,18 +226,18 @@ static int is64_type(int t)
/* instruction + 4 bytes data. Return the address of the data */
ST_FUNC int oad(int c, int s)
{
int ind1;
int t;
if (nocode_wanted)
return s;
o(c);
ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
write32le(cur_text_section->data + ind, s);
s = ind;
ind = ind1;
return s;
t = ind;
gen_le32(s);
return t;
}
/* generate jmp to a label */
#define gjmp2(instr,lbl) oad(instr,lbl)
ST_FUNC void gen_addr32(int r, Sym *sym, long c)
{
if (r & VT_SYM)
@ -1703,7 +1702,7 @@ void gfunc_epilog(void)
/* generate a jump to a label */
int gjmp(int t)
{
return psym(0xe9, t);
return gjmp2(0xe9, t);
}
/* generate a jump to a fixed address */
@ -1749,7 +1748,10 @@ ST_FUNC void gtst_addr(int inv, int a)
ST_FUNC int gtst(int inv, int t)
{
int v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
if (vtop->c.i & 0x100)
{
@ -1766,11 +1768,11 @@ ST_FUNC int gtst(int inv, int t)
else
{
g(0x0f);
t = psym(0x8a, t); /* jp t */
t = gjmp2(0x8a, t); /* jp t */
}
}
g(0x0f);
t = psym((vtop->c.i - 16) ^ inv, t);
t = gjmp2((vtop->c.i - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {