fold-const.c (fold_unary): New.

* fold-const.c (fold_unary): New.
	(fold): Call fold_unary on unary expressions.

From-SVN: r95783
This commit is contained in:
Kazu Hirata 2005-03-02 16:07:47 +00:00 committed by Kazu Hirata
parent 92fb2d32d5
commit 659d8efa54
2 changed files with 438 additions and 0 deletions

View File

@ -10,6 +10,9 @@
* expr.c (optimize_bitfield_assignment_op): Add a special case
to handle BIT_IOR_EXPR and BIT_XOR_EXPR.
* fold-const.c (fold_unary): New.
(fold): Call fold_unary on unary expressions.
2005-03-02 Richard Guenther <rguenth@gcc.gnu.org>
* cgraph.h (struct cgraph_edge): Add prev_caller and

View File

@ -6596,6 +6596,430 @@ fold_complex_div (tree type, tree ac, tree bc, enum tree_code code)
return fold_complex_div_parts (type, ar, ai, br, bi, code);
}
/* Fold a unary expression EXPR. Return the folded expression if
folding is successful. Otherwise, return the original
expression. */
static tree
fold_unary (tree expr)
{
const tree t = expr;
const tree type = TREE_TYPE (expr);
tree tem;
tree arg0;
enum tree_code code = TREE_CODE (t);
enum tree_code_class kind = TREE_CODE_CLASS (code);
gcc_assert (IS_EXPR_CODE_CLASS (kind)
&& TREE_CODE_LENGTH (code) == 1);
arg0 = TREE_OPERAND (t, 0);
if (arg0)
{
if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
{
/* Don't use STRIP_NOPS, because signedness of argument type matters. */
STRIP_SIGN_NOPS (arg0);
}
else
{
/* Strip any conversions that don't change the mode. This
is safe for every expression, except for a comparison
expression because its signedness is derived from its
operands.
Note that this is done as an internal manipulation within
the constant folder, in order to find the simplest
representation of the arguments so that their form can be
studied. In any cases, the appropriate type conversions
should be put back in the tree that will get out of the
constant folder. */
STRIP_NOPS (arg0);
}
}
if (TREE_CODE_CLASS (code) == tcc_unary)
{
if (TREE_CODE (arg0) == COMPOUND_EXPR)
return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
fold (build1 (code, type, TREE_OPERAND (arg0, 1))));
else if (TREE_CODE (arg0) == COND_EXPR)
{
tree arg01 = TREE_OPERAND (arg0, 1);
tree arg02 = TREE_OPERAND (arg0, 2);
if (! VOID_TYPE_P (TREE_TYPE (arg01)))
arg01 = fold (build1 (code, type, arg01));
if (! VOID_TYPE_P (TREE_TYPE (arg02)))
arg02 = fold (build1 (code, type, arg02));
tem = fold (build3 (COND_EXPR, type, TREE_OPERAND (arg0, 0),
arg01, arg02));
/* If this was a conversion, and all we did was to move into
inside the COND_EXPR, bring it back out. But leave it if
it is a conversion from integer to integer and the
result precision is no wider than a word since such a
conversion is cheap and may be optimized away by combine,
while it couldn't if it were outside the COND_EXPR. Then return
so we don't get into an infinite recursion loop taking the
conversion out and then back in. */
if ((code == NOP_EXPR || code == CONVERT_EXPR
|| code == NON_LVALUE_EXPR)
&& TREE_CODE (tem) == COND_EXPR
&& TREE_CODE (TREE_OPERAND (tem, 1)) == code
&& TREE_CODE (TREE_OPERAND (tem, 2)) == code
&& ! VOID_TYPE_P (TREE_OPERAND (tem, 1))
&& ! VOID_TYPE_P (TREE_OPERAND (tem, 2))
&& (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))
== TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0)))
&& (! (INTEGRAL_TYPE_P (TREE_TYPE (tem))
&& (INTEGRAL_TYPE_P
(TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))))
&& TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD)
|| flag_syntax_only))
tem = build1 (code, type,
build3 (COND_EXPR,
TREE_TYPE (TREE_OPERAND
(TREE_OPERAND (tem, 1), 0)),
TREE_OPERAND (tem, 0),
TREE_OPERAND (TREE_OPERAND (tem, 1), 0),
TREE_OPERAND (TREE_OPERAND (tem, 2), 0)));
return tem;
}
else if (COMPARISON_CLASS_P (arg0))
{
if (TREE_CODE (type) == BOOLEAN_TYPE)
{
arg0 = copy_node (arg0);
TREE_TYPE (arg0) = type;
return arg0;
}
else if (TREE_CODE (type) != INTEGER_TYPE)
return fold (build3 (COND_EXPR, type, arg0,
fold (build1 (code, type,
integer_one_node)),
fold (build1 (code, type,
integer_zero_node))));
}
}
switch (code)
{
case NOP_EXPR:
case FLOAT_EXPR:
case CONVERT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_CEIL_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
if (TREE_TYPE (TREE_OPERAND (t, 0)) == type)
return TREE_OPERAND (t, 0);
/* Handle cases of two conversions in a row. */
if (TREE_CODE (TREE_OPERAND (t, 0)) == NOP_EXPR
|| TREE_CODE (TREE_OPERAND (t, 0)) == CONVERT_EXPR)
{
tree inside_type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
tree inter_type = TREE_TYPE (TREE_OPERAND (t, 0));
int inside_int = INTEGRAL_TYPE_P (inside_type);
int inside_ptr = POINTER_TYPE_P (inside_type);
int inside_float = FLOAT_TYPE_P (inside_type);
unsigned int inside_prec = TYPE_PRECISION (inside_type);
int inside_unsignedp = TYPE_UNSIGNED (inside_type);
int inter_int = INTEGRAL_TYPE_P (inter_type);
int inter_ptr = POINTER_TYPE_P (inter_type);
int inter_float = FLOAT_TYPE_P (inter_type);
unsigned int inter_prec = TYPE_PRECISION (inter_type);
int inter_unsignedp = TYPE_UNSIGNED (inter_type);
int final_int = INTEGRAL_TYPE_P (type);
int final_ptr = POINTER_TYPE_P (type);
int final_float = FLOAT_TYPE_P (type);
unsigned int final_prec = TYPE_PRECISION (type);
int final_unsignedp = TYPE_UNSIGNED (type);
/* In addition to the cases of two conversions in a row
handled below, if we are converting something to its own
type via an object of identical or wider precision, neither
conversion is needed. */
if (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (type)
&& ((inter_int && final_int) || (inter_float && final_float))
&& inter_prec >= final_prec)
return fold (build1 (code, type,
TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
/* Likewise, if the intermediate and final types are either both
float or both integer, we don't need the middle conversion if
it is wider than the final type and doesn't change the signedness
(for integers). Avoid this if the final type is a pointer
since then we sometimes need the inner conversion. Likewise if
the outer has a precision not equal to the size of its mode. */
if ((((inter_int || inter_ptr) && (inside_int || inside_ptr))
|| (inter_float && inside_float))
&& inter_prec >= inside_prec
&& (inter_float || inter_unsignedp == inside_unsignedp)
&& ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_type))
&& ! final_ptr)
return fold (build1 (code, type,
TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
/* If we have a sign-extension of a zero-extended value, we can
replace that by a single zero-extension. */
if (inside_int && inter_int && final_int
&& inside_prec < inter_prec && inter_prec < final_prec
&& inside_unsignedp && !inter_unsignedp)
return fold (build1 (code, type,
TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
/* Two conversions in a row are not needed unless:
- some conversion is floating-point (overstrict for now), or
- the intermediate type is narrower than both initial and
final, or
- the intermediate type and innermost type differ in signedness,
and the outermost type is wider than the intermediate, or
- the initial type is a pointer type and the precisions of the
intermediate and final types differ, or
- the final type is a pointer type and the precisions of the
initial and intermediate types differ. */
if (! inside_float && ! inter_float && ! final_float
&& (inter_prec > inside_prec || inter_prec > final_prec)
&& ! (inside_int && inter_int
&& inter_unsignedp != inside_unsignedp
&& inter_prec < final_prec)
&& ((inter_unsignedp && inter_prec > inside_prec)
== (final_unsignedp && final_prec > inter_prec))
&& ! (inside_ptr && inter_prec != final_prec)
&& ! (final_ptr && inside_prec != inter_prec)
&& ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_type))
&& ! final_ptr)
return fold (build1 (code, type,
TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
}
if (TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR
&& TREE_CONSTANT (TREE_OPERAND (TREE_OPERAND (t, 0), 1))
/* Detect assigning a bitfield. */
&& !(TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 0), 0), 1))))
{
/* Don't leave an assignment inside a conversion
unless assigning a bitfield. */
tree prev = TREE_OPERAND (t, 0);
tem = copy_node (t);
TREE_OPERAND (tem, 0) = TREE_OPERAND (prev, 1);
/* First do the assignment, then return converted constant. */
tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), prev, fold (tem));
TREE_NO_WARNING (tem) = 1;
TREE_USED (tem) = 1;
return tem;
}
/* Convert (T)(x & c) into (T)x & (T)c, if c is an integer
constants (if x has signed type, the sign bit cannot be set
in c). This folds extension into the BIT_AND_EXPR. */
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (type) != BOOLEAN_TYPE
&& TREE_CODE (TREE_OPERAND (t, 0)) == BIT_AND_EXPR
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == INTEGER_CST)
{
tree and = TREE_OPERAND (t, 0);
tree and0 = TREE_OPERAND (and, 0), and1 = TREE_OPERAND (and, 1);
int change = 0;
if (TYPE_UNSIGNED (TREE_TYPE (and))
|| (TYPE_PRECISION (type)
<= TYPE_PRECISION (TREE_TYPE (and))))
change = 1;
else if (TYPE_PRECISION (TREE_TYPE (and1))
<= HOST_BITS_PER_WIDE_INT
&& host_integerp (and1, 1))
{
unsigned HOST_WIDE_INT cst;
cst = tree_low_cst (and1, 1);
cst &= (HOST_WIDE_INT) -1
<< (TYPE_PRECISION (TREE_TYPE (and1)) - 1);
change = (cst == 0);
#ifdef LOAD_EXTEND_OP
if (change
&& !flag_syntax_only
&& (LOAD_EXTEND_OP (TYPE_MODE (TREE_TYPE (and0)))
== ZERO_EXTEND))
{
tree uns = lang_hooks.types.unsigned_type (TREE_TYPE (and0));
and0 = fold_convert (uns, and0);
and1 = fold_convert (uns, and1);
}
#endif
}
if (change)
{
tem = build_int_cst_wide (type, TREE_INT_CST_LOW (and1),
TREE_INT_CST_HIGH (and1));
tem = force_fit_type (tem, 0, TREE_OVERFLOW (and1),
TREE_CONSTANT_OVERFLOW (and1));
return fold (build2 (BIT_AND_EXPR, type,
fold_convert (type, and0), tem));
}
}
/* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and
T2 being pointers to types of the same size. */
if (POINTER_TYPE_P (TREE_TYPE (t))
&& BINARY_CLASS_P (arg0)
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0))))
{
tree arg00 = TREE_OPERAND (arg0, 0);
tree t0 = TREE_TYPE (t);
tree t1 = TREE_TYPE (arg00);
tree tt0 = TREE_TYPE (t0);
tree tt1 = TREE_TYPE (t1);
tree s0 = TYPE_SIZE (tt0);
tree s1 = TYPE_SIZE (tt1);
if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST))
return build2 (TREE_CODE (arg0), t0, fold_convert (t0, arg00),
TREE_OPERAND (arg0, 1));
}
tem = fold_convert_const (code, type, arg0);
return tem ? tem : t;
case VIEW_CONVERT_EXPR:
if (TREE_CODE (TREE_OPERAND (t, 0)) == VIEW_CONVERT_EXPR)
return build1 (VIEW_CONVERT_EXPR, type,
TREE_OPERAND (TREE_OPERAND (t, 0), 0));
return t;
case NEGATE_EXPR:
if (negate_expr_p (arg0))
return fold_convert (type, negate_expr (arg0));
/* Convert - (~A) to A + 1. */
if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == BIT_NOT_EXPR)
return fold (build2 (PLUS_EXPR, type, TREE_OPERAND (arg0, 0),
build_int_cst (type, 1)));
return t;
case ABS_EXPR:
if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST)
return fold_abs_const (arg0, type);
else if (TREE_CODE (arg0) == NEGATE_EXPR)
return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0)));
/* Convert fabs((double)float) into (double)fabsf(float). */
else if (TREE_CODE (arg0) == NOP_EXPR
&& TREE_CODE (type) == REAL_TYPE)
{
tree targ0 = strip_float_extensions (arg0);
if (targ0 != arg0)
return fold_convert (type, fold (build1 (ABS_EXPR,
TREE_TYPE (targ0),
targ0)));
}
else if (tree_expr_nonnegative_p (arg0))
return arg0;
/* Strip sign ops from argument. */
if (TREE_CODE (type) == REAL_TYPE)
{
tem = fold_strip_sign_ops (arg0);
if (tem)
return fold (build1 (ABS_EXPR, type, fold_convert (type, tem)));
}
return t;
case CONJ_EXPR:
if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
return fold_convert (type, arg0);
else if (TREE_CODE (arg0) == COMPLEX_EXPR)
return build2 (COMPLEX_EXPR, type,
TREE_OPERAND (arg0, 0),
negate_expr (TREE_OPERAND (arg0, 1)));
else if (TREE_CODE (arg0) == COMPLEX_CST)
return build_complex (type, TREE_REALPART (arg0),
negate_expr (TREE_IMAGPART (arg0)));
else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
return fold (build2 (TREE_CODE (arg0), type,
fold (build1 (CONJ_EXPR, type,
TREE_OPERAND (arg0, 0))),
fold (build1 (CONJ_EXPR, type,
TREE_OPERAND (arg0, 1)))));
else if (TREE_CODE (arg0) == CONJ_EXPR)
return TREE_OPERAND (arg0, 0);
return t;
case BIT_NOT_EXPR:
if (TREE_CODE (arg0) == INTEGER_CST)
return fold_not_const (arg0, type);
else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
return TREE_OPERAND (arg0, 0);
/* Convert ~ (-A) to A - 1. */
else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
return fold (build2 (MINUS_EXPR, type, TREE_OPERAND (arg0, 0),
build_int_cst (type, 1)));
/* Convert ~ (A - 1) or ~ (A + -1) to -A. */
else if (INTEGRAL_TYPE_P (type)
&& ((TREE_CODE (arg0) == MINUS_EXPR
&& integer_onep (TREE_OPERAND (arg0, 1)))
|| (TREE_CODE (arg0) == PLUS_EXPR
&& integer_all_onesp (TREE_OPERAND (arg0, 1)))))
return fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0)));
return t;
case TRUTH_NOT_EXPR:
/* The argument to invert_truthvalue must have Boolean type. */
if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
arg0 = fold_convert (boolean_type_node, arg0);
/* Note that the operand of this must be an int
and its values must be 0 or 1.
("true" is a fixed value perhaps depending on the language,
but we don't handle values other than 1 correctly yet.) */
tem = invert_truthvalue (arg0);
/* Avoid infinite recursion. */
if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
return t;
return fold_convert (type, tem);
case REALPART_EXPR:
if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
return t;
else if (TREE_CODE (arg0) == COMPLEX_EXPR)
return omit_one_operand (type, TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg0, 1));
else if (TREE_CODE (arg0) == COMPLEX_CST)
return TREE_REALPART (arg0);
else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
return fold (build2 (TREE_CODE (arg0), type,
fold (build1 (REALPART_EXPR, type,
TREE_OPERAND (arg0, 0))),
fold (build1 (REALPART_EXPR, type,
TREE_OPERAND (arg0, 1)))));
return t;
case IMAGPART_EXPR:
if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
return fold_convert (type, integer_zero_node);
else if (TREE_CODE (arg0) == COMPLEX_EXPR)
return omit_one_operand (type, TREE_OPERAND (arg0, 1),
TREE_OPERAND (arg0, 0));
else if (TREE_CODE (arg0) == COMPLEX_CST)
return TREE_IMAGPART (arg0);
else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
return fold (build2 (TREE_CODE (arg0), type,
fold (build1 (IMAGPART_EXPR, type,
TREE_OPERAND (arg0, 0))),
fold (build1 (IMAGPART_EXPR, type,
TREE_OPERAND (arg0, 1)))));
return t;
default:
return t;
} /* switch (code) */
}
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
@ -6628,6 +7052,17 @@ fold (tree expr)
if (kind == tcc_constant)
return t;
if (IS_EXPR_CODE_CLASS (kind))
{
switch (TREE_CODE_LENGTH (code))
{
case 1:
return fold_unary (expr);
default:
break;
}
}
if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
{
tree subop;