aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c327
1 files changed, 276 insertions, 51 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index ef31a32f54e..47088743a71 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2004,16 +2004,12 @@ fold_convert (tree type, tree arg)
}
}
-/* Return an expr equal to X but certainly not valid as an lvalue. */
+/* Return false if expr can be assumed not to be an value, true
+ otherwise. */
-tree
-non_lvalue (tree x)
+static bool
+maybe_lvalue_p (tree x)
{
- /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
- us. */
- if (in_gimple_form)
- return x;
-
/* We only need to wrap lvalue tree codes. */
switch (TREE_CODE (x))
{
@@ -2053,8 +2049,24 @@ non_lvalue (tree x)
/* Assume the worst for front-end tree codes. */
if ((int)TREE_CODE (x) >= NUM_TREE_CODES)
break;
- return x;
+ return false;
}
+
+ return true;
+}
+
+/* Return an expr equal to X but certainly not valid as an lvalue. */
+
+tree
+non_lvalue (tree x)
+{
+ /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
+ us. */
+ if (in_gimple_form)
+ return x;
+
+ if (! maybe_lvalue_p (x))
+ return x;
return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
}
@@ -2936,8 +2948,7 @@ invert_truthvalue (tree arg)
switch (code)
{
case INTEGER_CST:
- return fold_convert (type,
- build_int_cst (NULL_TREE, integer_zerop (arg)));
+ return constant_boolean_node (integer_zerop (arg), type);
case TRUTH_AND_EXPR:
return build2 (TRUTH_OR_EXPR, type,
@@ -4267,7 +4278,13 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
a number and A is not. The conditions in the original
expressions will be false, so all four give B. The min()
and max() versions would give a NaN instead. */
- if (operand_equal_for_comparison_p (arg01, arg2, arg00))
+ if (operand_equal_for_comparison_p (arg01, arg2, arg00)
+ /* Avoid these transformations if the COND_EXPR may be used
+ as an lvalue in the C++ front-end. PR c++/19199. */
+ && (in_gimple_form
+ || strcmp (lang_hooks.name, "GNU C++") != 0
+ || ! maybe_lvalue_p (arg1)
+ || ! maybe_lvalue_p (arg2)))
{
tree comp_op0 = arg00;
tree comp_op1 = arg01;
@@ -5382,9 +5399,6 @@ constant_boolean_node (int value, tree type)
return value ? integer_one_node : integer_zero_node;
else if (type == boolean_type_node)
return value ? boolean_true_node : boolean_false_node;
- else if (TREE_CODE (type) == BOOLEAN_TYPE)
- return lang_hooks.truthvalue_conversion (value ? integer_one_node
- : integer_zero_node);
else
return build_int_cst (type, value);
}
@@ -6074,6 +6088,15 @@ fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
return NULL_TREE;
shorter_type = TREE_TYPE (arg0_unw);
+#ifdef HAVE_canonicalize_funcptr_for_compare
+ /* Disable this optimization if we're casting a function pointer
+ type on targets that require function pointer canonicalization. */
+ if (HAVE_canonicalize_funcptr_for_compare
+ && TREE_CODE (shorter_type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (shorter_type)) == FUNCTION_TYPE)
+ return NULL_TREE;
+#endif
+
if (TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (shorter_type))
return NULL_TREE;
@@ -6148,18 +6171,29 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
tree arg0_inner, tmp;
tree inner_type, outer_type;
- if (TREE_CODE (arg0) != NOP_EXPR)
+ if (TREE_CODE (arg0) != NOP_EXPR
+ && TREE_CODE (arg0) != CONVERT_EXPR)
return NULL_TREE;
outer_type = TREE_TYPE (arg0);
arg0_inner = TREE_OPERAND (arg0, 0);
inner_type = TREE_TYPE (arg0_inner);
+#ifdef HAVE_canonicalize_funcptr_for_compare
+ /* Disable this optimization if we're casting a function pointer
+ type on targets that require function pointer canonicalization. */
+ if (HAVE_canonicalize_funcptr_for_compare
+ && TREE_CODE (inner_type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE)
+ return NULL_TREE;
+#endif
+
if (TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
return NULL_TREE;
if (TREE_CODE (arg1) != INTEGER_CST
- && !(TREE_CODE (arg1) == NOP_EXPR
+ && !((TREE_CODE (arg1) == NOP_EXPR
+ || TREE_CODE (arg1) == CONVERT_EXPR)
&& TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type))
return NULL_TREE;
@@ -6180,7 +6214,7 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
else
arg1 = fold_convert (inner_type, arg1);
- return fold (build (code, type, arg0_inner, arg1));
+ return fold (build2 (code, type, arg0_inner, arg1));
}
/* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
@@ -6340,26 +6374,12 @@ fold_complex_add (tree type, tree ac, tree bc, enum tree_code code)
/* Perform some simplifications of complex multiplication when one or more
of the components are constants or zeros. Return non-null if successful. */
-static tree
-fold_complex_mult (tree type, tree ac, tree bc)
+tree
+fold_complex_mult_parts (tree type, tree ar, tree ai, tree br, tree bi)
{
- tree ar, ai, br, bi, rr, ri, inner_type, zero;
+ tree rr, ri, inner_type, zero;
bool ar0, ai0, br0, bi0, bi1;
- if (TREE_CODE (ac) == COMPLEX_EXPR)
- ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
- else if (TREE_CODE (ac) == COMPLEX_CST)
- ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
- else
- return NULL;
-
- if (TREE_CODE (bc) == COMPLEX_EXPR)
- br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
- else if (TREE_CODE (bc) == COMPLEX_CST)
- br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
- else
- return NULL;
-
inner_type = TREE_TYPE (type);
zero = NULL;
@@ -6436,7 +6456,7 @@ fold_complex_mult (tree type, tree ac, tree bc)
}
else if (ar0 && br0)
{
- rr = fold (build2 (MULT_EXPR, inner_type, ai, br));
+ rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
ri = zero;
}
@@ -6468,6 +6488,152 @@ fold_complex_mult (tree type, tree ac, tree bc)
return fold (build2 (COMPLEX_EXPR, type, rr, ri));
}
+static tree
+fold_complex_mult (tree type, tree ac, tree bc)
+{
+ tree ar, ai, br, bi;
+
+ if (TREE_CODE (ac) == COMPLEX_EXPR)
+ ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
+ else if (TREE_CODE (ac) == COMPLEX_CST)
+ ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
+ else
+ return NULL;
+
+ if (TREE_CODE (bc) == COMPLEX_EXPR)
+ br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
+ else if (TREE_CODE (bc) == COMPLEX_CST)
+ br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
+ else
+ return NULL;
+
+ return fold_complex_mult_parts (type, ar, ai, br, bi);
+}
+
+/* Perform some simplifications of complex division when one or more of
+ the components are constants or zeros. Return non-null if successful. */
+
+tree
+fold_complex_div_parts (tree type, tree ar, tree ai, tree br, tree bi,
+ enum tree_code code)
+{
+ tree rr, ri, inner_type, zero;
+ bool ar0, ai0, br0, bi0, bi1;
+
+ inner_type = TREE_TYPE (type);
+ zero = NULL;
+
+ if (SCALAR_FLOAT_TYPE_P (inner_type))
+ {
+ ar0 = ai0 = br0 = bi0 = bi1 = false;
+
+ /* We're only interested in +0.0 here, thus we don't use real_zerop. */
+
+ if (TREE_CODE (ar) == REAL_CST
+ && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ar), dconst0))
+ ar0 = true, zero = ar;
+
+ if (TREE_CODE (ai) == REAL_CST
+ && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ai), dconst0))
+ ai0 = true, zero = ai;
+
+ if (TREE_CODE (br) == REAL_CST
+ && REAL_VALUES_IDENTICAL (TREE_REAL_CST (br), dconst0))
+ br0 = true, zero = br;
+
+ if (TREE_CODE (bi) == REAL_CST)
+ {
+ if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst0))
+ bi0 = true, zero = bi;
+ else if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst1))
+ bi1 = true;
+ }
+ }
+ else
+ {
+ ar0 = integer_zerop (ar);
+ if (ar0)
+ zero = ar;
+ ai0 = integer_zerop (ai);
+ if (ai0)
+ zero = ai;
+ br0 = integer_zerop (br);
+ if (br0)
+ zero = br;
+ bi0 = integer_zerop (bi);
+ if (bi0)
+ {
+ zero = bi;
+ bi1 = false;
+ }
+ else
+ bi1 = integer_onep (bi);
+ }
+
+ /* We won't optimize anything below unless something is zero. */
+ if (zero == NULL)
+ return NULL;
+
+ if (ai0 && bi0)
+ {
+ rr = fold (build2 (code, inner_type, ar, br));
+ ri = zero;
+ }
+ else if (ai0 && br0)
+ {
+ rr = zero;
+ ri = fold (build2 (code, inner_type, ar, bi));
+ ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
+ }
+ else if (ar0 && bi0)
+ {
+ rr = zero;
+ ri = fold (build2 (code, inner_type, ai, br));
+ }
+ else if (ar0 && br0)
+ {
+ rr = fold (build2 (code, inner_type, ai, bi));
+ ri = zero;
+ }
+ else if (bi0)
+ {
+ rr = fold (build2 (code, inner_type, ar, br));
+ ri = fold (build2 (code, inner_type, ai, br));
+ }
+ else if (br0)
+ {
+ rr = fold (build2 (code, inner_type, ai, bi));
+ ri = fold (build2 (code, inner_type, ar, bi));
+ ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
+ }
+ else
+ return NULL;
+
+ return fold (build2 (COMPLEX_EXPR, type, rr, ri));
+}
+
+static tree
+fold_complex_div (tree type, tree ac, tree bc, enum tree_code code)
+{
+ tree ar, ai, br, bi;
+
+ if (TREE_CODE (ac) == COMPLEX_EXPR)
+ ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
+ else if (TREE_CODE (ac) == COMPLEX_CST)
+ ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
+ else
+ return NULL;
+
+ if (TREE_CODE (bc) == COMPLEX_EXPR)
+ br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
+ else if (TREE_CODE (bc) == COMPLEX_CST)
+ br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
+ else
+ return NULL;
+
+ return fold_complex_div_parts (type, ar, ai, br, bi, 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.
@@ -6484,7 +6650,8 @@ static
tree
fold (tree expr)
{
- const tree t = expr;
+ /* APPLE LOCAL altivec */
+ tree t = expr;
const tree type = TREE_TYPE (expr);
tree t1 = NULL_TREE;
tree tem;
@@ -6496,6 +6663,15 @@ fold (tree expr)
if all operands are constant. */
int wins = 1;
+ /* APPLE LOCAL begin AltiVec */
+ /* Fold constant comma expressions. */
+ while (TREE_CODE (t) == COMPOUND_EXPR && TREE_CONSTANT (t))
+ t = TREE_OPERAND (t, 1);
+
+ code = TREE_CODE (t);
+ kind = TREE_CODE_CLASS (code);
+ /* APPLE LOCAL end AltiVec */
+
/* Return right away if a constant. */
if (kind == tcc_constant)
return t;
@@ -6609,13 +6785,14 @@ fold (tree expr)
tem = fold (build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
: code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
: TRUTH_XOR_EXPR,
- type, fold_convert (boolean_type_node, arg0),
+ boolean_type_node,
+ fold_convert (boolean_type_node, arg0),
fold_convert (boolean_type_node, arg1)));
if (code == EQ_EXPR)
tem = invert_truthvalue (tem);
- return tem;
+ return fold_convert (type, tem);
}
if (TREE_CODE_CLASS (code) == tcc_unary)
@@ -6744,16 +6921,19 @@ fold (tree expr)
int inside_int = INTEGRAL_TYPE_P (inside_type);
int inside_ptr = POINTER_TYPE_P (inside_type);
int inside_float = FLOAT_TYPE_P (inside_type);
+ int inside_vec = TREE_CODE (inside_type) == VECTOR_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);
+ int inter_vec = TREE_CODE (inter_type) == VECTOR_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);
+ int final_vec = TREE_CODE (type) == VECTOR_TYPE;
unsigned int final_prec = TYPE_PRECISION (type);
int final_unsignedp = TYPE_UNSIGNED (type);
@@ -6774,12 +6954,15 @@ fold (tree expr)
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_float && inside_float)
+ || (inter_vec && inside_vec))
&& inter_prec >= inside_prec
- && (inter_float || inter_unsignedp == inside_unsignedp)
+ && (inter_float || inter_vec
+ || inter_unsignedp == inside_unsignedp)
&& ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_type))
- && ! final_ptr)
+ && ! final_ptr
+ && (! final_vec || inter_prec == inside_prec))
return fold (build1 (code, type,
TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
@@ -6793,6 +6976,7 @@ fold (tree expr)
/* Two conversions in a row are not needed unless:
- some conversion is floating-point (overstrict for now), or
+ - some conversion is a vector (overstrict for now), or
- the intermediate type is narrower than both initial and
final, or
- the intermediate type and innermost type differ in signedness,
@@ -6802,6 +6986,7 @@ fold (tree expr)
- the final type is a pointer type and the precisions of the
initial and intermediate types differ. */
if (! inside_float && ! inter_float && ! final_float
+ && ! inside_vec && ! inter_vec && ! final_vec
&& (inter_prec > inside_prec || inter_prec > final_prec)
&& ! (inside_int && inter_int
&& inter_unsignedp != inside_unsignedp
@@ -6874,9 +7059,14 @@ fold (tree expr)
#endif
}
if (change)
- return fold (build2 (BIT_AND_EXPR, type,
- fold_convert (type, and0),
- fold_convert (type, and1)));
+ {
+ 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
@@ -8041,6 +8231,13 @@ fold (tree expr)
TREE_OPERAND (arg1, 0)));
}
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ tem = fold_complex_div (type, arg0, arg1, code);
+ if (tem)
+ return tem;
+ }
+
if (flag_unsafe_math_optimizations)
{
enum built_in_function fcode = builtin_mathfn_code (arg1);
@@ -8165,6 +8362,12 @@ fold (tree expr)
code, NULL_TREE)))
return fold_convert (type, tem);
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ tem = fold_complex_div (type, arg0, arg1, code);
+ if (tem)
+ return tem;
+ }
goto binary;
case CEIL_MOD_EXPR:
@@ -8495,7 +8698,14 @@ fold (tree expr)
return non_lvalue (fold_convert (type, arg0));
/* If the second arg is constant true, this is a logical inversion. */
if (integer_onep (arg1))
- return non_lvalue (fold_convert (type, invert_truthvalue (arg0)));
+ {
+ /* Only call invert_truthvalue if operand is a truth value. */
+ if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
+ tem = fold (build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg0), arg0));
+ else
+ tem = invert_truthvalue (arg0);
+ return non_lvalue (fold_convert (type, tem));
+ }
/* Identical arguments cancel to zero. */
if (operand_equal_p (arg0, arg1, 0))
return omit_one_operand (type, integer_zero_node, arg0);
@@ -8948,7 +9158,8 @@ fold (tree expr)
TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)));
else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
- && TREE_CODE (arg0) == NOP_EXPR)
+ && (TREE_CODE (arg0) == NOP_EXPR
+ || TREE_CODE (arg0) == CONVERT_EXPR))
{
/* If we are widening one operand of an integer comparison,
see if the other operand is similarly being widened. Perhaps we
@@ -9759,8 +9970,11 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
expr = (tree) buf;
TYPE_POINTER_TO (expr) = NULL;
TYPE_REFERENCE_TO (expr) = NULL;
- TYPE_CACHED_VALUES_P (expr) = 0;
- TYPE_CACHED_VALUES (expr) = NULL;
+ if (TYPE_CACHED_VALUES_P (expr))
+ {
+ TYPE_CACHED_VALUES_P (expr) = 0;
+ TYPE_CACHED_VALUES (expr) = NULL;
+ }
}
md5_process_bytes (expr, tree_size (expr), ctx);
fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
@@ -11254,15 +11468,26 @@ fold_indirect_ref_1 (tree t)
/* *(foo *)&fooarray => fooarray[0] */
else if (TREE_CODE (optype) == ARRAY_TYPE
&& lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
- return build4 (ARRAY_REF, type, op, size_zero_node, NULL_TREE, NULL_TREE);
+ {
+ tree type_domain = TYPE_DOMAIN (optype);
+ tree min_val = size_zero_node;
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
+ }
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
&& lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
{
+ tree type_domain;
+ tree min_val = size_zero_node;
sub = build_fold_indirect_ref (sub);
- return build4 (ARRAY_REF, type, sub, size_zero_node, NULL_TREE, NULL_TREE);
+ type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
}
return NULL_TREE;