Rework expr_infix

- revert const-folding in gvtst() and put it back into
  expr_landor().  Although it did make sense, one reason
  not to do it is __builtin_constant_p() which may return
  true when it shouldn't because of nocode_wanted, see test.

- tccgen_init() can do init_prec(), also for tcc -E.

- for nostalgic reasons, keep the original expression parser
  functions in the source.

- Makefile: remove stale stuff
This commit is contained in:
grischka 2020-01-21 14:23:57 +01:00
parent aeac24de98
commit 7e901299bf
5 changed files with 191 additions and 82 deletions

View file

@ -238,20 +238,13 @@ XTCC ?= ./tcc$(EXESUF)
# TinyCC runtime libraries # TinyCC runtime libraries
libtcc1.a : tcc$(EXESUF) FORCE libtcc1.a : tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$T)' @$(MAKE) -C lib
# Cross libtcc1.a # Cross libtcc1.a
%-libtcc1.a : %-tcc$(EXESUF) FORCE %-libtcc1.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$* @$(MAKE) -C lib CROSS_TARGET=$*
# TinyCC runtime libraries .PRECIOUS: %-libtcc1.a
libtccb1.a : libtcc1.a
# Cross libtcc1.a
%-libtccb1.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
.PRECIOUS: %-libtcc1.a %-libtccb1.a
FORCE: FORCE:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------

1
tcc.h
View file

@ -1434,7 +1434,6 @@ ST_FUNC void parse_mult_str (CString *astr, const char *msg);
ST_FUNC void parse_asm_str(CString *astr); ST_FUNC void parse_asm_str(CString *astr);
ST_FUNC void indir(void); ST_FUNC void indir(void);
ST_FUNC void unary(void); ST_FUNC void unary(void);
ST_FUNC void init_prec(void);
ST_FUNC void gexpr(void); ST_FUNC void gexpr(void);
ST_FUNC int expr_const(void); ST_FUNC int expr_const(void);
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 #if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67

254
tccgen.c
View file

@ -67,7 +67,7 @@ static int gind(void) { CODE_ON(); return ind; }
/* Set 'nocode_wanted' after unconditional jumps */ /* Set 'nocode_wanted' after unconditional jumps */
static void gjmp_addr_acs(int t) { gjmp_addr(t); CODE_OFF(); } static void gjmp_addr_acs(int t) { gjmp_addr(t); CODE_OFF(); }
static int gjmp_acs(int t) { if (!nocode_wanted) {t = gjmp(t); CODE_OFF(); } return t; } static int gjmp_acs(int t) { t = gjmp(t); CODE_OFF(); return t; }
/* These are #undef'd at the end of this file */ /* These are #undef'd at the end of this file */
#define gjmp_addr gjmp_addr_acs #define gjmp_addr gjmp_addr_acs
@ -122,6 +122,11 @@ static struct scope {
Sym *lstk, *llstk; Sym *lstk, *llstk;
} *cur_scope, *loop_scope, *root_scope; } *cur_scope, *loop_scope, *root_scope;
/********************************************************/
#if 1
#define precedence_parser
static void init_prec(void);
#endif
/********************************************************/ /********************************************************/
#ifndef CONFIG_TCC_ASM #ifndef CONFIG_TCC_ASM
ST_FUNC void asm_instr(void) ST_FUNC void asm_instr(void)
@ -135,7 +140,6 @@ ST_FUNC void asm_global_instr(void)
#endif #endif
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static void gen_cast(CType *type); static void gen_cast(CType *type);
static void gen_cast_s(int t); static void gen_cast_s(int t);
static inline CType *pointed_type(CType *type); static inline CType *pointed_type(CType *type);
@ -455,6 +459,9 @@ ST_FUNC void tccgen_init(TCCState *s1)
func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0);
func_old_type.ref->f.func_call = FUNC_CDECL; func_old_type.ref->f.func_call = FUNC_CDECL;
func_old_type.ref->f.func_type = FUNC_OLD; func_old_type.ref->f.func_type = FUNC_OLD;
#ifdef precedence_parser
init_prec();
#endif
} }
ST_FUNC int tccgen_compile(TCCState *s1) ST_FUNC int tccgen_compile(TCCState *s1)
@ -877,7 +884,7 @@ static void vcheck_cmp(void)
again, so that the VT_CMP/VT_JMP value will be in vtop again, so that the VT_CMP/VT_JMP value will be in vtop
when code is unsuppressed again. */ when code is unsuppressed again. */
if (vtop->r == VT_CMP && !nocode_wanted && vtop->cmp_op > 1) if (vtop->r == VT_CMP && !nocode_wanted)
gv(RC_INT); gv(RC_INT);
} }
@ -1040,14 +1047,11 @@ ST_FUNC void vset_VT_CMP(int op)
static void vset_VT_JMP(void) static void vset_VT_JMP(void)
{ {
int op = vtop->cmp_op; int op = vtop->cmp_op;
if (vtop->jtrue || vtop->jfalse) { if (vtop->jtrue || vtop->jfalse) {
/* we need to jump to 'mov $0,%R' or 'mov $1,%R' */ /* we need to jump to 'mov $0,%R' or 'mov $1,%R' */
int inv = op & (op < 2); /* small optimization */ int inv = op & (op < 2); /* small optimization */
int t = gvtst(inv, 0); vseti(VT_JMP+inv, gvtst(inv, 0));
if (t) /* in case gvtst only needed to do a gsym */
vseti(VT_JMP+inv, t);
else
vpushi(inv);
} else { } else {
/* otherwise convert flags (rsp. 0/1) to register */ /* otherwise convert flags (rsp. 0/1) to register */
vtop->c.i = op; vtop->c.i = op;
@ -1060,18 +1064,14 @@ static void vset_VT_JMP(void)
static void gvtst_set(int inv, int t) static void gvtst_set(int inv, int t)
{ {
int *p; int *p;
if (vtop->r != VT_CMP) { if (vtop->r != VT_CMP) {
vpushi(0); vpushi(0);
gen_op(TOK_NE); gen_op(TOK_NE);
if (vtop->r == VT_CMP) /* must be VT_CONST otherwise */ if (vtop->r != VT_CMP) /* must be VT_CONST then */
;
else if (vtop->r == VT_CONST) {
if (!t)
return;
vset_VT_CMP(vtop->c.i != 0); vset_VT_CMP(vtop->c.i != 0);
} else
tcc_error("ICE");
} }
p = inv ? &vtop->jfalse : &vtop->jtrue; p = inv ? &vtop->jfalse : &vtop->jtrue;
*p = gjmp_append(*p, t); *p = gjmp_append(*p, t);
} }
@ -1082,20 +1082,16 @@ static void gvtst_set(int inv, int t)
static int gvtst(int inv, int t) static int gvtst(int inv, int t)
{ {
int op, x, u; int op, x, u;
gvtst_set(inv, t); gvtst_set(inv, t);
if (vtop->r != VT_CMP) { t = vtop->jtrue, u = vtop->jfalse;
t = u = x = 0; if (inv)
op = vtop->c.i; x = u, u = t, t = x;
} else { op = vtop->cmp_op;
t = vtop->jtrue, u = vtop->jfalse;
if (inv)
x = u, u = t, t = x;
op = vtop->cmp_op;
}
/* jump to the wanted target */ /* jump to the wanted target */
if (op > 1) if (op > 1)
t = gjmp_cond(op ^ inv, t), op = inv;//, op = 1; t = gjmp_cond(op ^ inv, t);
else if (op != inv) else if (op != inv)
t = gjmp(t); t = gjmp(t);
/* resolve complementary jumps to here */ /* resolve complementary jumps to here */
@ -5690,22 +5686,120 @@ special_math_val:
} }
} }
/* Assuming vtop is a value used in a conditional context #ifndef precedence_parser /* original top-down parser */
(i.e. compared with zero) return 0 if it's false, 1 if
true and -1 if it can't be statically determined. */ static void expr_prod(void)
static int condition_3way(void)
{ {
int c = -1; int t;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
(!(vtop->r & VT_SYM) || !vtop->sym->a.weak)) { unary();
vdup(); while ((t = tok) == '*' || t == '/' || t == '%') {
gen_cast_s(VT_BOOL); next();
c = vtop->c.i; unary();
vpop(); gen_op(t);
} }
return c;
} }
static void expr_sum(void)
{
int t;
expr_prod();
while ((t = tok) == '+' || t == '-') {
next();
expr_prod();
gen_op(t);
}
}
static void expr_shift(void)
{
int t;
expr_sum();
while ((t = tok) == TOK_SHL || t == TOK_SAR) {
next();
expr_sum();
gen_op(t);
}
}
static void expr_cmp(void)
{
int t;
expr_shift();
while (((t = tok) >= TOK_ULE && t <= TOK_GT) ||
t == TOK_ULT || t == TOK_UGE) {
next();
expr_shift();
gen_op(t);
}
}
static void expr_cmpeq(void)
{
int t;
expr_cmp();
while ((t = tok) == TOK_EQ || t == TOK_NE) {
next();
expr_cmp();
gen_op(t);
}
}
static void expr_and(void)
{
expr_cmpeq();
while (tok == '&') {
next();
expr_cmpeq();
gen_op('&');
}
}
static void expr_xor(void)
{
expr_and();
while (tok == '^') {
next();
expr_and();
gen_op('^');
}
}
static void expr_or(void)
{
expr_xor();
while (tok == '|') {
next();
expr_xor();
gen_op('|');
}
}
static void expr_landor(int op);
static void expr_land(void)
{
expr_or();
if (tok == TOK_LAND)
expr_landor(tok);
}
static void expr_lor(void)
{
expr_land();
if (tok == TOK_LOR)
expr_landor(tok);
}
# define expr_landor_next(op) op == TOK_LAND ? expr_or() : expr_land()
#else /* defined precedence_parser */
# define expr_landor_next(op) unary(), expr_infix(precedence(op) + 1)
# define expr_lor() unary(), expr_infix(1)
static int precedence(int tok) static int precedence(int tok)
{ {
switch (tok) { switch (tok) {
@ -5725,44 +5819,23 @@ static int precedence(int tok)
return 0; return 0;
} }
} }
static unsigned char prec[256]; static unsigned char prec[256];
ST_FUNC void init_prec(void) static void init_prec(void)
{ {
int i; int i;
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
prec[i] = precedence(i); prec[i] = precedence(i);
} }
#define precedence(i) ((unsigned)i < 256 ? prec[i] : 0) #define precedence(i) ((unsigned)i < 256 ? prec[i] : 0)
static void expr_infix(int p); static void expr_landor(int op);
static void expr_landor(int p, int e_op, int i)
{
int t = 0, f = 0;
save_regs(1);
do {
if (!f && condition_3way() == !i)
nocode_wanted++, f = 1;
t = gvtst(i, t);
next();
unary();
expr_infix(p);
} while (tok == e_op);
if (f) {
vpop();
vpushi(i ^ f);
}
gvtst_set(i, t);
nocode_wanted -= f;
}
static void expr_infix(int p) static void expr_infix(int p)
{ {
int t = tok, p2; int t = tok, p2;
while ((p2 = precedence(t)) >= p) { while ((p2 = precedence(t)) >= p) {
if (t == TOK_LOR || t == TOK_LAND) { if (t == TOK_LOR || t == TOK_LAND) {
expr_landor(p2 + 1, t, t == TOK_LAND); expr_landor(t);
} else { } else {
next(); next();
unary(); unary();
@ -5773,6 +5846,51 @@ static void expr_infix(int p)
t = tok; t = tok;
} }
} }
#endif
/* Assuming vtop is a value used in a conditional context
(i.e. compared with zero) return 0 if it's false, 1 if
true and -1 if it can't be statically determined. */
static int condition_3way(void)
{
int c = -1;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
(!(vtop->r & VT_SYM) || !vtop->sym->a.weak)) {
vdup();
gen_cast_s(VT_BOOL);
c = vtop->c.i;
vpop();
}
return c;
}
static void expr_landor(int op)
{
int t = 0, cc = 1, f = 0, i = op == TOK_LAND, c;
for(;;) {
c = f ? i : condition_3way();
if (c < 0)
save_regs(1), cc = 0;
else if (c != i)
nocode_wanted++, f = 1;
if (tok != op)
break;
if (c < 0)
t = gvtst(i, t);
else
vpop();
next();
expr_landor_next(op);
}
if (cc || f) {
vpop();
vpushi(i ^ f);
gsym(t);
nocode_wanted -= f;
} else {
gvtst_set(i, t);
}
}
static int is_cond_bool(SValue *sv) static int is_cond_bool(SValue *sv)
{ {
@ -5791,11 +5909,11 @@ static void expr_cond(void)
CType type, type1, type2; CType type, type1, type2;
int ncw_prev; int ncw_prev;
unary(); expr_lor();
expr_infix(1);
if (tok == '?') { if (tok == '?') {
next(); next();
c = condition_3way(); c = condition_3way();
ncw_prev = nocode_wanted;
g = (tok == ':' && gnu_ext); g = (tok == ':' && gnu_ext);
tt = 0; tt = 0;
if (!g) { if (!g) {
@ -5813,7 +5931,6 @@ static void expr_cond(void)
tt = gvtst(0, 0); tt = gvtst(0, 0);
} }
ncw_prev = nocode_wanted;
if (1) { if (1) {
if (c == 0) if (c == 0)
nocode_wanted++; nocode_wanted++;
@ -6013,12 +6130,11 @@ static void expr_eq(void)
int t; int t;
expr_cond(); expr_cond();
if (tok == '=' || if ((t = tok) == '='
(tok >= TOK_A_MOD && tok <= TOK_A_DIV) || || (t >= TOK_A_MOD && t <= TOK_A_DIV)
tok == TOK_A_XOR || tok == TOK_A_OR || || t == TOK_A_XOR || t == TOK_A_OR
tok == TOK_A_SHL || tok == TOK_A_SAR) { || t == TOK_A_SHL || t == TOK_A_SAR) {
test_lvalue(); test_lvalue();
t = tok;
next(); next();
if (t == '=') { if (t == '=') {
expr_eq(); expr_eq();

View file

@ -3679,8 +3679,6 @@ ST_FUNC void tccpp_new(TCCState *s)
define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL); define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
init_prec();
} }
ST_FUNC void tccpp_delete(TCCState *s) ST_FUNC void tccpp_delete(TCCState *s)

View file

@ -3736,6 +3736,9 @@ void builtin_test(void)
printf("res = %d\n", __builtin_constant_p(&constant_p_var)); printf("res = %d\n", __builtin_constant_p(&constant_p_var));
printf("res = %d\n", __builtin_constant_p(constant_p_var)); printf("res = %d\n", __builtin_constant_p(constant_p_var));
printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var)); printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var));
printf("res = %d\n", __builtin_constant_p(i && 0));
printf("res = %d\n", __builtin_constant_p(i && 1));
printf("res = %d\n", __builtin_constant_p(i && 0 ? i : 34));
s = 1; s = 1;
ll = 2; ll = 2;
i = __builtin_choose_expr (1 != 0, ll, s); i = __builtin_choose_expr (1 != 0, ll, s);