fold-const.c (comparison_to_compcode): New function to convert an comparison TREE CODE into a bit-based representation.

* fold-const.c (comparison_to_compcode): New function to convert
	an comparison TREE CODE into a bit-based representation.
	(compcode_to_comparison): New function to convert from this bit
	based representation back to a comparison TREE CODE.
	(fold_truthop): Simplify (x<y) && (x==y) and related composite
	comparisons.

	* gcc.c-tortuture/execute/compare-1.c: New test case.
	* gcc.c-tortuture/execute/compare-2.c: New test case.
	* gcc.c-tortuture/execute/compare-3.c: New test case.

From-SVN: r54647
This commit is contained in:
Roger Sayle 2002-06-15 16:55:24 +00:00 committed by Roger Sayle
parent f7d3c5f005
commit 8dcb27ed86
6 changed files with 355 additions and 0 deletions

View file

@ -1,3 +1,12 @@
2002-06-15 Roger Sayle <roger@eyesopen.com>
* fold-const.c (comparison_to_compcode): New function to convert
an comparison TREE CODE into a bit-based representation.
(compcode_to_comparison): New function to convert from this bit
based representation back to a comparison TREE CODE.
(fold_truthop): Simplify (x<y) && (x==y) and related composite
comparisons.
2002-06-15 Aldy Hernandez <aldyh@redhat.com>
* tm.texi (MEMBER_TYPE_FORCES_BLK): Document MODE argument.

View file

@ -72,6 +72,8 @@ static int size_htab_eq PARAMS ((const void *, const void *));
static tree fold_convert PARAMS ((tree, tree));
static enum tree_code invert_tree_comparison PARAMS ((enum tree_code));
static enum tree_code swap_tree_comparison PARAMS ((enum tree_code));
static int comparison_to_compcode PARAMS ((enum tree_code));
static enum tree_code compcode_to_comparison PARAMS ((int));
static int truth_value_p PARAMS ((enum tree_code));
static int operand_equal_for_comparison_p PARAMS ((tree, tree, tree));
static int twoval_comparison_p PARAMS ((tree, tree *, tree *, int *));
@ -115,6 +117,18 @@ static bool fold_real_zero_addition_p PARAMS ((tree, tree, int));
#define CHARMASK 0x7f
#endif
/* The following constants represent a bit based encoding of GCC's
comparison operators. This encoding simplifies transformations
on relational comparison operators, such as AND and OR. */
#define COMPCODE_FALSE 0
#define COMPCODE_LT 1
#define COMPCODE_EQ 2
#define COMPCODE_LE 3
#define COMPCODE_GT 4
#define COMPCODE_NE 5
#define COMPCODE_GE 6
#define COMPCODE_TRUE 7
/* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
overflow. Suppose A, B and SUM have the same respective signs as A1, B1,
and SUM1. Then this yields nonzero if overflow occurred during the
@ -1709,6 +1723,61 @@ swap_tree_comparison (code)
}
}
/* Convert a comparison tree code from an enum tree_code representation
into a compcode bit-based encoding. This function is the inverse of
compcode_to_comparison. */
static int
comparison_to_compcode (code)
enum tree_code code;
{
switch (code)
{
case LT_EXPR:
return COMPCODE_LT;
case EQ_EXPR:
return COMPCODE_EQ;
case LE_EXPR:
return COMPCODE_LE;
case GT_EXPR:
return COMPCODE_GT;
case NE_EXPR:
return COMPCODE_NE;
case GE_EXPR:
return COMPCODE_GE;
default:
abort ();
}
}
/* Convert a compcode bit-based encoding of a comparison operator back
to GCC's enum tree_code representation. This function is the
inverse of comparison_to_compcode. */
static enum tree_code
compcode_to_comparison (code)
int code;
{
switch (code)
{
case COMPCODE_LT:
return LT_EXPR;
case COMPCODE_EQ:
return EQ_EXPR;
case COMPCODE_LE:
return LE_EXPR;
case COMPCODE_GT:
return GT_EXPR;
case COMPCODE_NE:
return NE_EXPR;
case COMPCODE_GE:
return GE_EXPR;
default:
abort ();
}
}
/* Return nonzero if CODE is a tree code that represents a truth value. */
static int
@ -3498,6 +3567,48 @@ fold_truthop (code, truth_type, lhs, rhs)
rl_arg = TREE_OPERAND (rhs, 0);
rr_arg = TREE_OPERAND (rhs, 1);
/* Simplify (x<y) && (x==y) into (x<=y) and related optimizations. */
if (simple_operand_p (ll_arg)
&& simple_operand_p (lr_arg)
&& !FLOAT_TYPE_P (TREE_TYPE (ll_arg)))
{
int compcode;
if (operand_equal_p (ll_arg, rl_arg, 0)
&& operand_equal_p (lr_arg, rr_arg, 0))
{
int lcompcode, rcompcode;
lcompcode = comparison_to_compcode (lcode);
rcompcode = comparison_to_compcode (rcode);
compcode = (code == TRUTH_AND_EXPR)
? lcompcode & rcompcode
: lcompcode | rcompcode;
}
else if (operand_equal_p (ll_arg, rr_arg, 0)
&& operand_equal_p (lr_arg, rl_arg, 0))
{
int lcompcode, rcompcode;
rcode = swap_tree_comparison (rcode);
lcompcode = comparison_to_compcode (lcode);
rcompcode = comparison_to_compcode (rcode);
compcode = (code == TRUTH_AND_EXPR)
? lcompcode & rcompcode
: lcompcode | rcompcode;
}
else
compcode = -1;
if (compcode == COMPCODE_TRUE)
return convert (truth_type, integer_one_node);
else if (compcode == COMPCODE_FALSE)
return convert (truth_type, integer_zero_node);
else if (compcode != -1)
return build (compcode_to_comparison (compcode),
truth_type, ll_arg, lr_arg);
}
/* If the RHS can be evaluated unconditionally and its operands are
simple, it wins to evaluate the RHS unconditionally on machines
with expensive branches. In this case, this isn't a comparison

View file

@ -1,3 +1,9 @@
2002-06-15 Roger Sayle <roger@eyesopen.com>
* gcc.c-tortuture/execute/compare-1.c: New test case.
* gcc.c-tortuture/execute/compare-2.c: New test case.
* gcc.c-tortuture/execute/compare-3.c: New test case.
2002-06-13 Richard Henderson <rth@redhat.com>
* g++.old-deja/g++.abi/vtable2.C (INC_VDATA): New. Define for

View file

@ -0,0 +1,119 @@
/* Copyright (C) 2002 Free Software Foundation.
Test for correctness of composite comparisons.
Written by Roger Sayle, 3rd June 2002. */
extern void abort (void);
int ieq (int x, int y, int ok)
{
if ((x<=y) && (x>=y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
if ((x<=y) && (x==y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
if ((x<=y) && (y<=x))
{
if (!ok) abort ();
}
else
if (ok) abort ();
if ((y==x) && (x<=y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int ine (int x, int y, int ok)
{
if ((x<y) || (x>y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int ilt (int x, int y, int ok)
{
if ((x<y) && (x!=y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int ile (int x, int y, int ok)
{
if ((x<y) || (x==y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int igt (int x, int y, int ok)
{
if ((x>y) && (x!=y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int ige (int x, int y, int ok)
{
if ((x>y) || (x==y))
{
if (!ok) abort ();
}
else
if (ok) abort ();
}
int
main ()
{
ieq (1, 4, 0);
ieq (3, 3, 1);
ieq (5, 2, 0);
ine (1, 4, 1);
ine (3, 3, 0);
ine (5, 2, 1);
ilt (1, 4, 1);
ilt (3, 3, 0);
ilt (5, 2, 0);
ile (1, 4, 1);
ile (3, 3, 1);
ile (5, 2, 0);
igt (1, 4, 0);
igt (3, 3, 0);
igt (5, 2, 1);
ige (1, 4, 0);
ige (3, 3, 1);
ige (5, 2, 1);
return 0;
}

View file

@ -0,0 +1,24 @@
/* Copyright (C) 2002 Free Software Foundation.
Ensure that the composite comparison optimization doesn't misfire
and attempt to combine a signed comparison with an unsigned one.
Written by Roger Sayle, 3rd June 2002. */
extern void abort (void);
int
foo (int x, int y)
{
/* If miscompiled the following may become "x == y". */
return (x<=y) && ((unsigned int)x >= (unsigned int)y);
}
int
main ()
{
if (! foo (-1,0))
abort ();
return 0;
}

View file

@ -0,0 +1,86 @@
/* Copyright (C) 2002 Free Software Foundation.
Test for composite comparison always true/false optimization.
Written by Roger Sayle, 7th June 2002. */
extern void link_error0 ();
extern void link_error1 ();
void
test1 (int x, int y)
{
if ((x==y) && (x!=y))
link_error0();
}
void
test2 (int x, int y)
{
if ((x<y) && (x>y))
link_error0();
}
void
test3 (int x, int y)
{
if ((x<y) && (y<x))
link_error0();
}
void
test4 (int x, int y)
{
if ((x==y) || (x!=y))
{
}
else
link_error1 ();
}
void
test5 (int x, int y)
{
if ((x>=y) || (x<y))
{
}
else
link_error1 ();
}
void
test6 (int x, int y)
{
if ((x<=y) || (y<x))
{
}
else
link_error1 ();
}
void
all_tests (int x, int y)
{
test1 (x, y);
test2 (x, y);
test3 (x, y);
test4 (x, y);
test5 (x, y);
test6 (x, y);
}
int
main ()
{
all_tests (0, 0);
all_tests (1, 2);
all_tests (4, 3);
return 0;
}
#ifndef __OPTIMIZE__
void link_error0() {}
void link_error1() {}
#endif /* ! __OPTIMIZE__ */