1
0
Fork 0

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
libtcc1.a : tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$T)'
@$(MAKE) -C lib
# Cross libtcc1.a
%-libtcc1.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
@$(MAKE) -C lib CROSS_TARGET=$*
# TinyCC runtime libraries
libtccb1.a : libtcc1.a
# Cross libtcc1.a
%-libtccb1.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
.PRECIOUS: %-libtcc1.a %-libtccb1.a
.PRECIOUS: %-libtcc1.a
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 indir(void);
ST_FUNC void unary(void);
ST_FUNC void init_prec(void);
ST_FUNC void gexpr(void);
ST_FUNC int expr_const(void);
#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 */
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 */
#define gjmp_addr gjmp_addr_acs
@ -122,6 +122,11 @@ static struct scope {
Sym *lstk, *llstk;
} *cur_scope, *loop_scope, *root_scope;
/********************************************************/
#if 1
#define precedence_parser
static void init_prec(void);
#endif
/********************************************************/
#ifndef CONFIG_TCC_ASM
ST_FUNC void asm_instr(void)
@ -135,7 +140,6 @@ ST_FUNC void asm_global_instr(void)
#endif
/* ------------------------------------------------------------------------- */
static void gen_cast(CType *type);
static void gen_cast_s(int t);
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->f.func_call = FUNC_CDECL;
func_old_type.ref->f.func_type = FUNC_OLD;
#ifdef precedence_parser
init_prec();
#endif
}
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
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);
}
@ -1040,14 +1047,11 @@ ST_FUNC void vset_VT_CMP(int op)
static void vset_VT_JMP(void)
{
int op = vtop->cmp_op;
if (vtop->jtrue || vtop->jfalse) {
/* we need to jump to 'mov $0,%R' or 'mov $1,%R' */
int inv = op & (op < 2); /* small optimization */
int t = gvtst(inv, 0);
if (t) /* in case gvtst only needed to do a gsym */
vseti(VT_JMP+inv, t);
else
vpushi(inv);
vseti(VT_JMP+inv, gvtst(inv, 0));
} else {
/* otherwise convert flags (rsp. 0/1) to register */
vtop->c.i = op;
@ -1060,18 +1064,14 @@ static void vset_VT_JMP(void)
static void gvtst_set(int inv, int t)
{
int *p;
if (vtop->r != VT_CMP) {
vpushi(0);
gen_op(TOK_NE);
if (vtop->r == VT_CMP) /* must be VT_CONST otherwise */
;
else if (vtop->r == VT_CONST) {
if (!t)
return;
if (vtop->r != VT_CMP) /* must be VT_CONST then */
vset_VT_CMP(vtop->c.i != 0);
} else
tcc_error("ICE");
}
p = inv ? &vtop->jfalse : &vtop->jtrue;
*p = gjmp_append(*p, t);
}
@ -1082,20 +1082,16 @@ static void gvtst_set(int inv, int t)
static int gvtst(int inv, int t)
{
int op, x, u;
gvtst_set(inv, t);
if (vtop->r != VT_CMP) {
t = u = x = 0;
op = vtop->c.i;
} else {
t = vtop->jtrue, u = vtop->jfalse;
if (inv)
x = u, u = t, t = x;
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 */
if (op > 1)
t = gjmp_cond(op ^ inv, t), op = inv;//, op = 1;
t = gjmp_cond(op ^ inv, t);
else if (op != inv)
t = gjmp(t);
/* resolve complementary jumps to here */
@ -5690,22 +5686,120 @@ special_math_val:
}
}
/* 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)
#ifndef precedence_parser /* original top-down parser */
static void expr_prod(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();
int t;
unary();
while ((t = tok) == '*' || t == '/' || t == '%') {
next();
unary();
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)
{
switch (tok) {
@ -5725,44 +5819,23 @@ static int precedence(int tok)
return 0;
}
}
static unsigned char prec[256];
ST_FUNC void init_prec(void)
static void init_prec(void)
{
int i;
for (i = 0; i < 256; i++)
prec[i] = precedence(i);
}
#define precedence(i) ((unsigned)i < 256 ? prec[i] : 0)
static void expr_infix(int p);
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_landor(int op);
static void expr_infix(int p)
{
int t = tok, p2;
while ((p2 = precedence(t)) >= p) {
if (t == TOK_LOR || t == TOK_LAND) {
expr_landor(p2 + 1, t, t == TOK_LAND);
expr_landor(t);
} else {
next();
unary();
@ -5773,6 +5846,51 @@ static void expr_infix(int p)
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)
{
@ -5791,11 +5909,11 @@ static void expr_cond(void)
CType type, type1, type2;
int ncw_prev;
unary();
expr_infix(1);
expr_lor();
if (tok == '?') {
next();
c = condition_3way();
ncw_prev = nocode_wanted;
g = (tok == ':' && gnu_ext);
tt = 0;
if (!g) {
@ -5813,7 +5931,6 @@ static void expr_cond(void)
tt = gvtst(0, 0);
}
ncw_prev = nocode_wanted;
if (1) {
if (c == 0)
nocode_wanted++;
@ -6013,12 +6130,11 @@ static void expr_eq(void)
int t;
expr_cond();
if (tok == '=' ||
(tok >= TOK_A_MOD && tok <= TOK_A_DIV) ||
tok == TOK_A_XOR || tok == TOK_A_OR ||
tok == TOK_A_SHL || tok == TOK_A_SAR) {
if ((t = tok) == '='
|| (t >= TOK_A_MOD && t <= TOK_A_DIV)
|| t == TOK_A_XOR || t == TOK_A_OR
|| t == TOK_A_SHL || t == TOK_A_SAR) {
test_lvalue();
t = tok;
next();
if (t == '=') {
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___TIME__, MACRO_OBJ, NULL, NULL);
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
init_prec();
}
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(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;
ll = 2;
i = __builtin_choose_expr (1 != 0, ll, s);