/* Fold a constant sub-tree into a single node for C-compiler
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "flags.h"
+#include "backend.h"
+#include "predict.h"
#include "tree.h"
+#include "gimple.h"
+#include "rtl.h"
+#include "flags.h"
+#include "alias.h"
+#include "fold-const.h"
#include "stor-layout.h"
#include "calls.h"
#include "tree-iterator.h"
#include "realmpfr.h"
-#include "rtl.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
#include "tm_p.h"
#include "target.h"
#include "intl.h"
#include "langhooks.h"
#include "md5.h"
-#include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "hard-reg-set.h"
-#include "input.h"
-#include "function.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "tree-eh.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "gimple.h"
#include "gimplify.h"
#include "tree-dfa.h"
-#include "hash-table.h" /* Required for ENABLE_FOLD_CHECKING. */
#include "builtins.h"
-#include "hash-map.h"
-#include "plugin-api.h"
-#include "ipa-ref.h"
#include "cgraph.h"
#include "generic-match.h"
-#include "optabs.h"
+#include "optabs-query.h"
+#include "gimple-fold.h"
+#include "params.h"
+#include "tree-ssa-operands.h"
+#include "tree-into-ssa.h"
+
+#ifndef LOAD_EXTEND_OP
+#define LOAD_EXTEND_OP(M) UNKNOWN
+#endif
/* Nonzero if we are folding constants inside an initializer; zero
otherwise. */
COMPCODE_TRUE = 15
};
-static bool negate_mathfn_p (enum built_in_function);
static bool negate_expr_p (tree);
static tree negate_expr (tree);
static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
static int operand_equal_for_comparison_p (tree, tree, tree);
static int twoval_comparison_p (tree, tree *, tree *, int *);
static tree eval_subst (location_t, tree, tree, tree, tree, tree);
-static tree distribute_bit_expr (location_t, enum tree_code, tree, tree, tree);
static tree make_bit_field_ref (location_t, tree, tree,
HOST_WIDE_INT, HOST_WIDE_INT, int);
static tree optimize_bit_field_compare (location_t, enum tree_code,
enum tree_code, tree,
tree, tree,
tree, tree, int);
-static tree fold_mathfn_compare (location_t,
- enum built_in_function, enum tree_code,
- tree, tree, tree);
-static tree fold_inf_compare (location_t, enum tree_code, tree, tree, tree);
static tree fold_div_compare (location_t, enum tree_code, tree, tree, tree);
static bool reorder_operands_p (const_tree, const_tree);
static tree fold_negate_const (tree, tree);
deferred code. */
void
-fold_undefer_overflow_warnings (bool issue, const_gimple stmt, int code)
+fold_undefer_overflow_warnings (bool issue, const gimple *stmt, int code)
{
const char *warnmsg;
location_t locus;
/* Return true if the built-in mathematical function specified by CODE
is odd, i.e. -f(x) == f(-x). */
-static bool
+bool
negate_mathfn_p (enum built_in_function code)
{
switch (code)
switch (TREE_CODE (t))
{
case INTEGER_CST:
- if (TYPE_OVERFLOW_WRAPS (type))
+ if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type))
return true;
/* Check that -CST will not overflow type. */
case INTEGER_CST:
tem = fold_negate_const (t, type);
if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t)
- || (!TYPE_OVERFLOW_TRAPS (type)
+ || (ANY_INTEGRAL_TYPE_P (type)
+ && !TYPE_OVERFLOW_TRAPS (type)
&& TYPE_OVERFLOW_WRAPS (type))
|| (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
return tem;
/* Don't perform operation if it would raise a division
by zero exception. */
if (code == RDIV_EXPR
- && REAL_VALUES_EQUAL (d2, dconst0)
+ && real_equal (&d2, &dconst0)
&& (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
return NULL_TREE;
default:;
}
+ if (TREE_CODE_CLASS (code) != tcc_binary)
+ return NULL_TREE;
+
/* Make sure type and arg0 have the same saturating flag. */
gcc_checking_assert (TYPE_SATURATING (type)
== TYPE_SATURATING (TREE_TYPE (arg1)));
+
return const_binop (code, arg1, arg2);
}
{
tree lt = TYPE_MIN_VALUE (type);
REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt);
- if (REAL_VALUES_LESS (r, l))
+ if (real_less (&r, &l))
{
overflow = true;
val = lt;
if (ut)
{
REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut);
- if (REAL_VALUES_LESS (u, r))
+ if (real_less (&u, &r))
{
overflow = true;
val = ut;
enum tree_code rcode, tree truth_type,
tree ll_arg, tree lr_arg)
{
- bool honor_nans = HONOR_NANS (element_mode (ll_arg));
+ bool honor_nans = HONOR_NANS (ll_arg);
enum comparison_code lcompcode = comparison_to_compcode (lcode);
enum comparison_code rcompcode = comparison_to_compcode (rcode);
int compcode;
If OEP_PURE_SAME is set, then pure functions with identical arguments
are considered the same. It is used when the caller has other ways
- to ensure that global memory is unchanged in between. */
+ to ensure that global memory is unchanged in between.
+
+ If OEP_ADDRESS_OF is set, we are actually comparing addresses of objects,
+ not values of expressions. OEP_CONSTANT_ADDRESS_OF in addition to
+ OEP_ADDRESS_OF is used for ADDR_EXPR with TREE_CONSTANT flag set and we
+ further ignore any side effects on SAVE_EXPRs then. */
int
operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
/* Check equality of integer constants before bailing out due to
precision differences. */
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
- return tree_int_cst_equal (arg0, arg1);
-
- /* If both types don't have the same signedness, then we can't consider
- them equal. We must check this before the STRIP_NOPS calls
- because they may change the signedness of the arguments. As pointers
- strictly don't have a signedness, require either two pointers or
- two non-pointers as well. */
- if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))
- || POINTER_TYPE_P (TREE_TYPE (arg0)) != POINTER_TYPE_P (TREE_TYPE (arg1)))
- return 0;
+ {
+ /* Address of INTEGER_CST is not defined; check that we did not forget
+ to drop the OEP_ADDRESS_OF/OEP_CONSTANT_ADDRESS_OF flags. */
+ gcc_checking_assert (!(flags
+ & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF)));
+ return tree_int_cst_equal (arg0, arg1);
+ }
- /* We cannot consider pointers to different address space equal. */
- if (POINTER_TYPE_P (TREE_TYPE (arg0)) && POINTER_TYPE_P (TREE_TYPE (arg1))
- && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
- != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))
- return 0;
+ if (!(flags & OEP_ADDRESS_OF))
+ {
+ /* If both types don't have the same signedness, then we can't consider
+ them equal. We must check this before the STRIP_NOPS calls
+ because they may change the signedness of the arguments. As pointers
+ strictly don't have a signedness, require either two pointers or
+ two non-pointers as well. */
+ if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))
+ || POINTER_TYPE_P (TREE_TYPE (arg0))
+ != POINTER_TYPE_P (TREE_TYPE (arg1)))
+ return 0;
- /* If both types don't have the same precision, then it is not safe
- to strip NOPs. */
- if (element_precision (TREE_TYPE (arg0))
- != element_precision (TREE_TYPE (arg1)))
- return 0;
+ /* We cannot consider pointers to different address space equal. */
+ if (POINTER_TYPE_P (TREE_TYPE (arg0))
+ && POINTER_TYPE_P (TREE_TYPE (arg1))
+ && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
+ != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))
+ return 0;
- STRIP_NOPS (arg0);
- STRIP_NOPS (arg1);
+ /* If both types don't have the same precision, then it is not safe
+ to strip NOPs. */
+ if (element_precision (TREE_TYPE (arg0))
+ != element_precision (TREE_TYPE (arg1)))
+ return 0;
+
+ STRIP_NOPS (arg0);
+ STRIP_NOPS (arg1);
+ }
+#if 0
+ /* FIXME: Fortran FE currently produce ADDR_EXPR of NOP_EXPR. Enable the
+ sanity check once the issue is solved. */
+ else
+ /* Addresses of conversions and SSA_NAMEs (and many other things)
+ are not defined. Check that we did not forget to drop the
+ OEP_ADDRESS_OF/OEP_CONSTANT_ADDRESS_OF flags. */
+ gcc_checking_assert (!CONVERT_EXPR_P (arg0) && !CONVERT_EXPR_P (arg1)
+ && TREE_CODE (arg0) != SSA_NAME);
+#endif
/* In case both args are comparisons but with different comparison
code, try to swap the comparison operands of one arg to produce
TREE_OPERAND (arg1, 0), flags);
}
- if (TREE_CODE (arg0) != TREE_CODE (arg1)
+ if (TREE_CODE (arg0) != TREE_CODE (arg1))
+ {
/* NOP_EXPR and CONVERT_EXPR are considered equal. */
- && !(CONVERT_EXPR_P (arg0) && CONVERT_EXPR_P (arg1)))
- return 0;
+ if (CONVERT_EXPR_P (arg0) && CONVERT_EXPR_P (arg1))
+ ;
+ else if (flags & OEP_ADDRESS_OF)
+ {
+ /* If we are interested in comparing addresses ignore
+ MEM_REF wrappings of the base that can appear just for
+ TBAA reasons. */
+ if (TREE_CODE (arg0) == MEM_REF
+ && DECL_P (arg1)
+ && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR
+ && TREE_OPERAND (TREE_OPERAND (arg0, 0), 0) == arg1
+ && integer_zerop (TREE_OPERAND (arg0, 1)))
+ return 1;
+ else if (TREE_CODE (arg1) == MEM_REF
+ && DECL_P (arg0)
+ && TREE_CODE (TREE_OPERAND (arg1, 0)) == ADDR_EXPR
+ && TREE_OPERAND (TREE_OPERAND (arg1, 0), 0) == arg0
+ && integer_zerop (TREE_OPERAND (arg1, 1)))
+ return 1;
+ return 0;
+ }
+ else
+ return 0;
+ }
/* This is needed for conversions and for COMPONENT_REF.
Might as well play it safe and always test this. */
TREE_FIXED_CST (arg1));
case REAL_CST:
- if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (arg0),
- TREE_REAL_CST (arg1)))
+ if (real_identical (&TREE_REAL_CST (arg0), &TREE_REAL_CST (arg1)))
return 1;
- if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0))))
+ if (!HONOR_SIGNED_ZEROS (arg0))
{
/* If we do not distinguish between signed and unsigned zero,
consider them equal. */
TREE_STRING_LENGTH (arg0)));
case ADDR_EXPR:
+ gcc_checking_assert (!(flags
+ & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF)));
return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
- TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)
- ? OEP_CONSTANT_ADDRESS_OF : 0);
+ flags | OEP_ADDRESS_OF
+ | OEP_CONSTANT_ADDRESS_OF);
+ case CONSTRUCTOR:
+ /* In GIMPLE empty constructors are allowed in initializers of
+ aggregates. */
+ return (!vec_safe_length (CONSTRUCTOR_ELTS (arg0))
+ && !vec_safe_length (CONSTRUCTOR_ELTS (arg1)));
default:
break;
}
switch (TREE_CODE (arg0))
{
case INDIRECT_REF:
- flags &= ~OEP_CONSTANT_ADDRESS_OF;
+ if (!(flags & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF))
+ && (TYPE_ALIGN (TREE_TYPE (arg0))
+ != TYPE_ALIGN (TREE_TYPE (arg1))))
+ return 0;
+ flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
return OP_SAME (0);
case REALPART_EXPR:
return OP_SAME (0);
case TARGET_MEM_REF:
- flags &= ~OEP_CONSTANT_ADDRESS_OF;
- /* Require equal extra operands and then fall through to MEM_REF
- handling of the two common operands. */
- if (!OP_SAME_WITH_NULL (2)
- || !OP_SAME_WITH_NULL (3)
- || !OP_SAME_WITH_NULL (4))
- return 0;
- /* Fallthru. */
case MEM_REF:
- flags &= ~OEP_CONSTANT_ADDRESS_OF;
- /* Require equal access sizes, and similar pointer types.
- We can have incomplete types for array references of
- variable-sized arrays from the Fortran frontend
- though. Also verify the types are compatible. */
- return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1))
- || (TYPE_SIZE (TREE_TYPE (arg0))
- && TYPE_SIZE (TREE_TYPE (arg1))
- && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
- TYPE_SIZE (TREE_TYPE (arg1)), flags)))
- && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
- && alias_ptr_types_compatible_p
- (TREE_TYPE (TREE_OPERAND (arg0, 1)),
- TREE_TYPE (TREE_OPERAND (arg1, 1)))
- && OP_SAME (0) && OP_SAME (1));
+ if (!(flags & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF)))
+ {
+ /* Require equal access sizes */
+ if (TYPE_SIZE (TREE_TYPE (arg0)) != TYPE_SIZE (TREE_TYPE (arg1))
+ && (!TYPE_SIZE (TREE_TYPE (arg0))
+ || !TYPE_SIZE (TREE_TYPE (arg1))
+ || !operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
+ TYPE_SIZE (TREE_TYPE (arg1)),
+ flags)))
+ return 0;
+ /* Verify that access happens in similar types. */
+ if (!types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1)))
+ return 0;
+ /* Verify that accesses are TBAA compatible. */
+ if (flag_strict_aliasing
+ && (!alias_ptr_types_compatible_p
+ (TREE_TYPE (TREE_OPERAND (arg0, 1)),
+ TREE_TYPE (TREE_OPERAND (arg1, 1)))
+ || (MR_DEPENDENCE_CLIQUE (arg0)
+ != MR_DEPENDENCE_CLIQUE (arg1))
+ || (MR_DEPENDENCE_BASE (arg0)
+ != MR_DEPENDENCE_BASE (arg1))))
+ return 0;
+ /* Verify that alignment is compatible. */
+ if (TYPE_ALIGN (TREE_TYPE (arg0))
+ != TYPE_ALIGN (TREE_TYPE (arg1)))
+ return 0;
+ }
+ flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
+ return (OP_SAME (0) && OP_SAME (1)
+ /* TARGET_MEM_REF require equal extra operands. */
+ && (TREE_CODE (arg0) != TARGET_MEM_REF
+ || (OP_SAME_WITH_NULL (2)
+ && OP_SAME_WITH_NULL (3)
+ && OP_SAME_WITH_NULL (4))));
case ARRAY_REF:
case ARRAY_RANGE_REF:
may have different types but same value here. */
if (!OP_SAME (0))
return 0;
- flags &= ~OEP_CONSTANT_ADDRESS_OF;
+ flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
return ((tree_int_cst_equal (TREE_OPERAND (arg0, 1),
TREE_OPERAND (arg1, 1))
|| OP_SAME (1))
if (!OP_SAME_WITH_NULL (0)
|| !OP_SAME (1))
return 0;
- flags &= ~OEP_CONSTANT_ADDRESS_OF;
+ flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
return OP_SAME_WITH_NULL (2);
case BIT_FIELD_REF:
if (!OP_SAME (0))
return 0;
- flags &= ~OEP_CONSTANT_ADDRESS_OF;
+ flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
return OP_SAME (1) && OP_SAME (2);
default:
switch (TREE_CODE (arg0))
{
case ADDR_EXPR:
+ /* Be sure we pass right ADDRESS_OF flag. */
+ gcc_checking_assert (!(flags
+ & (OEP_ADDRESS_OF
+ | OEP_CONSTANT_ADDRESS_OF)));
+ return operand_equal_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg1, 0),
+ flags | OEP_ADDRESS_OF);
+
case TRUTH_NOT_EXPR:
return OP_SAME (0);
switch (TREE_CODE (arg0))
{
case CALL_EXPR:
- /* If the CALL_EXPRs call different functions, then they
- clearly can not be equal. */
- if (! operand_equal_p (CALL_EXPR_FN (arg0), CALL_EXPR_FN (arg1),
- flags))
+ if ((CALL_EXPR_FN (arg0) == NULL_TREE)
+ != (CALL_EXPR_FN (arg1) == NULL_TREE))
+ /* If not both CALL_EXPRs are either internal or normal function
+ functions, then they are not equal. */
return 0;
+ else if (CALL_EXPR_FN (arg0) == NULL_TREE)
+ {
+ /* If the CALL_EXPRs call different internal functions, then they
+ are not equal. */
+ if (CALL_EXPR_IFN (arg0) != CALL_EXPR_IFN (arg1))
+ return 0;
+ }
+ else
+ {
+ /* If the CALL_EXPRs call different functions, then they are not
+ equal. */
+ if (! operand_equal_p (CALL_EXPR_FN (arg0), CALL_EXPR_FN (arg1),
+ flags))
+ return 0;
+ }
{
unsigned int cef = call_expr_flags (arg0);
&& DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1)
&& DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1));
+ case tcc_exceptional:
+ if (TREE_CODE (arg0) == CONSTRUCTOR)
+ {
+ /* In GIMPLE constructors are used only to build vectors from
+ elements. Individual elements in the constructor must be
+ indexed in increasing order and form an initial sequence.
+
+ We make no effort to compare constructors in generic.
+ (see sem_variable::equals in ipa-icf which can do so for
+ constants). */
+ if (!VECTOR_TYPE_P (TREE_TYPE (arg0))
+ || !VECTOR_TYPE_P (TREE_TYPE (arg1)))
+ return 0;
+
+ /* Be sure that vectors constructed have the same representation.
+ We only tested element precision and modes to match.
+ Vectors may be BLKmode and thus also check that the number of
+ parts match. */
+ if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0))
+ != TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)))
+ return 0;
+
+ vec<constructor_elt, va_gc> *v0 = CONSTRUCTOR_ELTS (arg0);
+ vec<constructor_elt, va_gc> *v1 = CONSTRUCTOR_ELTS (arg1);
+ unsigned int len = vec_safe_length (v0);
+
+ if (len != vec_safe_length (v1))
+ return 0;
+
+ for (unsigned int i = 0; i < len; i++)
+ {
+ constructor_elt *c0 = &(*v0)[i];
+ constructor_elt *c1 = &(*v1)[i];
+
+ if (!operand_equal_p (c0->value, c1->value, flags)
+ /* In GIMPLE the indexes can be either NULL or matching i.
+ Double check this so we won't get false
+ positives for GENERIC. */
+ || (c0->index
+ && (TREE_CODE (c0->index) != INTEGER_CST
+ || !compare_tree_int (c0->index, i)))
+ || (c1->index
+ && (TREE_CODE (c1->index) != INTEGER_CST
+ || !compare_tree_int (c1->index, i))))
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+
default:
return 0;
}
&& code != NE_EXPR && code != EQ_EXPR)
return NULL_TREE;
- code = invert_tree_comparison (code, HONOR_NANS (TYPE_MODE (op_type)));
+ code = invert_tree_comparison (code, HONOR_NANS (op_type));
if (code == ERROR_MARK)
return NULL_TREE;
type, arg);
}
-/* Given a bit-wise operation CODE applied to ARG0 and ARG1, see if both
- operands are another bit-wise operation with a common input. If so,
- distribute the bit operations to save an operation and possibly two if
- constants are involved. For example, convert
- (A | B) & (A | C) into A | (B & C)
- Further simplification will occur if B and C are constants.
-
- If this optimization cannot be done, 0 will be returned. */
-
-static tree
-distribute_bit_expr (location_t loc, enum tree_code code, tree type,
- tree arg0, tree arg1)
-{
- tree common;
- tree left, right;
-
- if (TREE_CODE (arg0) != TREE_CODE (arg1)
- || TREE_CODE (arg0) == code
- || (TREE_CODE (arg0) != BIT_AND_EXPR
- && TREE_CODE (arg0) != BIT_IOR_EXPR))
- return 0;
-
- if (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0))
- {
- common = TREE_OPERAND (arg0, 0);
- left = TREE_OPERAND (arg0, 1);
- right = TREE_OPERAND (arg1, 1);
- }
- else if (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 1), 0))
- {
- common = TREE_OPERAND (arg0, 0);
- left = TREE_OPERAND (arg0, 1);
- right = TREE_OPERAND (arg1, 0);
- }
- else if (operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 0), 0))
- {
- common = TREE_OPERAND (arg0, 1);
- left = TREE_OPERAND (arg0, 0);
- right = TREE_OPERAND (arg1, 1);
- }
- else if (operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1), 0))
- {
- common = TREE_OPERAND (arg0, 1);
- left = TREE_OPERAND (arg0, 0);
- right = TREE_OPERAND (arg1, 0);
- }
- else
- return 0;
-
- common = fold_convert_loc (loc, type, common);
- left = fold_convert_loc (loc, type, left);
- right = fold_convert_loc (loc, type, right);
- return fold_build2_loc (loc, TREE_CODE (arg0), type, common,
- fold_build2_loc (loc, code, type, left, right));
-}
-
/* Knowing that ARG0 and ARG1 are both RDIV_EXPRs, simplify a binary operation
with code CODE. This optimization is unsafe. */
static tree
{
tree etype = TREE_TYPE (exp), value;
-#ifdef HAVE_canonicalize_funcptr_for_compare
/* Disable this optimization for function pointer expressions
on targets that require function pointer canonicalization. */
- if (HAVE_canonicalize_funcptr_for_compare
+ if (targetm.have_canonicalize_funcptr_for_compare ()
&& TREE_CODE (etype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (etype)) == FUNCTION_TYPE)
return NULL_TREE;
-#endif
if (! in_p)
{
operand which will be used if they are equal first
so that we can convert this back to the
corresponding COND_EXPR. */
- if (!HONOR_NANS (element_mode (arg1)))
+ if (!HONOR_NANS (arg1))
{
comp_op0 = fold_convert_loc (loc, comp_type, comp_op0);
comp_op1 = fold_convert_loc (loc, comp_type, comp_op1);
case GT_EXPR:
case UNGE_EXPR:
case UNGT_EXPR:
- if (!HONOR_NANS (element_mode (arg1)))
+ if (!HONOR_NANS (arg1))
{
comp_op0 = fold_convert_loc (loc, comp_type, comp_op0);
comp_op1 = fold_convert_loc (loc, comp_type, comp_op1);
}
break;
case UNEQ_EXPR:
- if (!HONOR_NANS (element_mode (arg1)))
+ if (!HONOR_NANS (arg1))
return pedantic_non_lvalue_loc (loc,
fold_convert_loc (loc, type, arg2));
break;
case LTGT_EXPR:
- if (!HONOR_NANS (element_mode (arg1)))
+ if (!HONOR_NANS (arg1))
return pedantic_non_lvalue_loc (loc,
fold_convert_loc (loc, type, arg1));
break;
}
}
- inv_code = invert_tree_comparison (code, HONOR_NANS (TYPE_MODE (type)));
+ inv_code = invert_tree_comparison (code, HONOR_NANS (type));
if (inv_code == rhs_code
&& operand_equal_p (TREE_OPERAND (rhs, 0), TREE_OPERAND (cmpop, 0), 0)
&& operand_equal_p (TREE_OPERAND (rhs, 1), TREE_OPERAND (cmpop, 1), 0))
|| EXPRESSION_CLASS_P (op0))
/* ... and has wrapping overflow, and its type is smaller
than ctype, then we cannot pass through as widening. */
- && ((TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0))
+ && (((ANY_INTEGRAL_TYPE_P (TREE_TYPE (op0))
+ && TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0)))
&& (TYPE_PRECISION (ctype)
> TYPE_PRECISION (TREE_TYPE (op0))))
/* ... or this is a truncation (t is narrower than op0),
/* ... or has undefined overflow while the converted to
type has not, we cannot do the operation in the inner type
as that would introduce undefined overflow. */
- || (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0))
+ || ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (op0))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)))
&& !TYPE_OVERFLOW_UNDEFINED (type))))
break;
/* If OP1 was not easily negatable, the constant may be OP0. */
if (TREE_CODE (op0) == INTEGER_CST)
{
- tree tem = op0;
- op0 = op1;
- op1 = tem;
- tem = t1;
- t1 = t2;
- t2 = tem;
+ std::swap (op0, op1);
+ std::swap (t1, t2);
}
}
&& ((sign == UNSIGNED && tcode != MULT_EXPR) || sign == SIGNED))
overflow_p = true;
if (!overflow_p)
- return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
- wide_int_to_tree (ctype, mul));
+ {
+ mul = wide_int::from (mul, TYPE_PRECISION (ctype),
+ TYPE_SIGN (TREE_TYPE (op1)));
+ return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
+ wide_int_to_tree (ctype, mul));
+ }
}
/* If these operations "cancel" each other, we have the main
return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type));
}
-/* Subroutine of fold() that checks comparisons of built-in math
- functions against real constants.
-
- FCODE is the DECL_FUNCTION_CODE of the built-in, CODE is the comparison
- operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, GE_EXPR or LE_EXPR. TYPE
- is the type of the result and ARG0 and ARG1 are the operands of the
- comparison. ARG1 must be a TREE_REAL_CST.
-
- The function returns the constant folded tree if a simplification
- can be made, and NULL_TREE otherwise. */
-
-static tree
-fold_mathfn_compare (location_t loc,
- enum built_in_function fcode, enum tree_code code,
- tree type, tree arg0, tree arg1)
-{
- REAL_VALUE_TYPE c;
-
- if (BUILTIN_SQRT_P (fcode))
- {
- tree arg = CALL_EXPR_ARG (arg0, 0);
- machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
-
- c = TREE_REAL_CST (arg1);
- if (REAL_VALUE_NEGATIVE (c))
- {
- /* sqrt(x) < y is always false, if y is negative. */
- if (code == EQ_EXPR || code == LT_EXPR || code == LE_EXPR)
- return omit_one_operand_loc (loc, type, integer_zero_node, arg);
-
- /* sqrt(x) > y is always true, if y is negative and we
- don't care about NaNs, i.e. negative values of x. */
- if (code == NE_EXPR || !HONOR_NANS (mode))
- return omit_one_operand_loc (loc, type, integer_one_node, arg);
-
- /* sqrt(x) > y is the same as x >= 0, if y is negative. */
- return fold_build2_loc (loc, GE_EXPR, type, arg,
- build_real (TREE_TYPE (arg), dconst0));
- }
- else if (code == GT_EXPR || code == GE_EXPR)
- {
- REAL_VALUE_TYPE c2;
-
- REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
- real_convert (&c2, mode, &c2);
-
- if (REAL_VALUE_ISINF (c2))
- {
- /* sqrt(x) > y is x == +Inf, when y is very large. */
- if (HONOR_INFINITIES (mode))
- return fold_build2_loc (loc, EQ_EXPR, type, arg,
- build_real (TREE_TYPE (arg), c2));
-
- /* sqrt(x) > y is always false, when y is very large
- and we don't care about infinities. */
- return omit_one_operand_loc (loc, type, integer_zero_node, arg);
- }
-
- /* sqrt(x) > c is the same as x > c*c. */
- return fold_build2_loc (loc, code, type, arg,
- build_real (TREE_TYPE (arg), c2));
- }
- else if (code == LT_EXPR || code == LE_EXPR)
- {
- REAL_VALUE_TYPE c2;
-
- REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
- real_convert (&c2, mode, &c2);
-
- if (REAL_VALUE_ISINF (c2))
- {
- /* sqrt(x) < y is always true, when y is a very large
- value and we don't care about NaNs or Infinities. */
- if (! HONOR_NANS (mode) && ! HONOR_INFINITIES (mode))
- return omit_one_operand_loc (loc, type, integer_one_node, arg);
-
- /* sqrt(x) < y is x != +Inf when y is very large and we
- don't care about NaNs. */
- if (! HONOR_NANS (mode))
- return fold_build2_loc (loc, NE_EXPR, type, arg,
- build_real (TREE_TYPE (arg), c2));
-
- /* sqrt(x) < y is x >= 0 when y is very large and we
- don't care about Infinities. */
- if (! HONOR_INFINITIES (mode))
- return fold_build2_loc (loc, GE_EXPR, type, arg,
- build_real (TREE_TYPE (arg), dconst0));
-
- /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */
- arg = save_expr (arg);
- return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type,
- fold_build2_loc (loc, GE_EXPR, type, arg,
- build_real (TREE_TYPE (arg),
- dconst0)),
- fold_build2_loc (loc, NE_EXPR, type, arg,
- build_real (TREE_TYPE (arg),
- c2)));
- }
-
- /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */
- if (! HONOR_NANS (mode))
- return fold_build2_loc (loc, code, type, arg,
- build_real (TREE_TYPE (arg), c2));
-
- /* sqrt(x) < c is the same as x >= 0 && x < c*c. */
- arg = save_expr (arg);
- return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type,
- fold_build2_loc (loc, GE_EXPR, type, arg,
- build_real (TREE_TYPE (arg),
- dconst0)),
- fold_build2_loc (loc, code, type, arg,
- build_real (TREE_TYPE (arg),
- c2)));
- }
- }
-
- return NULL_TREE;
-}
-
-/* Subroutine of fold() that optimizes comparisons against Infinities,
- either +Inf or -Inf.
-
- CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR,
- GE_EXPR or LE_EXPR. TYPE is the type of the result and ARG0 and ARG1
- are the operands of the comparison. ARG1 must be a TREE_REAL_CST.
-
- The function returns the constant folded tree if a simplification
- can be made, and NULL_TREE otherwise. */
-
-static tree
-fold_inf_compare (location_t loc, enum tree_code code, tree type,
- tree arg0, tree arg1)
-{
- machine_mode mode;
- REAL_VALUE_TYPE max;
- tree temp;
- bool neg;
-
- mode = TYPE_MODE (TREE_TYPE (arg0));
-
- /* For negative infinity swap the sense of the comparison. */
- neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1));
- if (neg)
- code = swap_tree_comparison (code);
-
- switch (code)
- {
- case GT_EXPR:
- /* x > +Inf is always false, if with ignore sNANs. */
- if (HONOR_SNANS (mode))
- return NULL_TREE;
- return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
-
- case LE_EXPR:
- /* x <= +Inf is always true, if we don't case about NaNs. */
- if (! HONOR_NANS (mode))
- return omit_one_operand_loc (loc, type, integer_one_node, arg0);
-
- /* x <= +Inf is the same as x == x, i.e. isfinite(x). */
- arg0 = save_expr (arg0);
- return fold_build2_loc (loc, EQ_EXPR, type, arg0, arg0);
-
- case EQ_EXPR:
- case GE_EXPR:
- /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */
- real_maxval (&max, neg, mode);
- return fold_build2_loc (loc, neg ? LT_EXPR : GT_EXPR, type,
- arg0, build_real (TREE_TYPE (arg0), max));
-
- case LT_EXPR:
- /* x < +Inf is always equal to x <= DBL_MAX. */
- real_maxval (&max, neg, mode);
- return fold_build2_loc (loc, neg ? GE_EXPR : LE_EXPR, type,
- arg0, build_real (TREE_TYPE (arg0), max));
-
- case NE_EXPR:
- /* x != +Inf is always equal to !(x > DBL_MAX). */
- real_maxval (&max, neg, mode);
- if (! HONOR_NANS (mode))
- return fold_build2_loc (loc, neg ? GE_EXPR : LE_EXPR, type,
- arg0, build_real (TREE_TYPE (arg0), max));
-
- temp = fold_build2_loc (loc, neg ? LT_EXPR : GT_EXPR, type,
- arg0, build_real (TREE_TYPE (arg0), max));
- return fold_build1_loc (loc, TRUTH_NOT_EXPR, type, temp);
-
- default:
- break;
- }
-
- return NULL_TREE;
-}
-
/* Subroutine of fold() that optimizes comparisons of a division by
a nonzero integer constant against an integer constant, i.e.
X/C1 op C2.
/* If we are going to be able to omit the AND below, we must do our
operations as unsigned. If we must use the AND, we have a choice.
Normally unsigned is faster, but for some machines signed is. */
-#ifdef LOAD_EXTEND_OP
ops_unsigned = (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND
&& !flag_syntax_only) ? 0 : 1;
-#else
- ops_unsigned = 1;
-#endif
signed_type = lang_hooks.types.type_for_mode (operand_mode, 0);
unsigned_type = lang_hooks.types.type_for_mode (operand_mode, 1);
return 0;
}
-/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where
- ARG0 is extended to a wider type. */
-
-static tree
-fold_widened_comparison (location_t loc, enum tree_code code,
- tree type, tree arg0, tree arg1)
-{
- tree arg0_unw = get_unwidened (arg0, NULL_TREE);
- tree arg1_unw;
- tree shorter_type, outer_type;
- tree min, max;
- bool above, below;
-
- if (arg0_unw == arg0)
- 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;
-
- arg1_unw = get_unwidened (arg1, NULL_TREE);
-
- /* If possible, express the comparison in the shorter mode. */
- if ((code == EQ_EXPR || code == NE_EXPR
- || TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type))
- && (TREE_TYPE (arg1_unw) == shorter_type
- || ((TYPE_PRECISION (shorter_type)
- >= TYPE_PRECISION (TREE_TYPE (arg1_unw)))
- && (TYPE_UNSIGNED (shorter_type)
- == TYPE_UNSIGNED (TREE_TYPE (arg1_unw))))
- || (TREE_CODE (arg1_unw) == INTEGER_CST
- && (TREE_CODE (shorter_type) == INTEGER_TYPE
- || TREE_CODE (shorter_type) == BOOLEAN_TYPE)
- && int_fits_type_p (arg1_unw, shorter_type))))
- return fold_build2_loc (loc, code, type, arg0_unw,
- fold_convert_loc (loc, shorter_type, arg1_unw));
-
- if (TREE_CODE (arg1_unw) != INTEGER_CST
- || TREE_CODE (shorter_type) != INTEGER_TYPE
- || !int_fits_type_p (arg1_unw, shorter_type))
- return NULL_TREE;
-
- /* If we are comparing with the integer that does not fit into the range
- of the shorter type, the result is known. */
- outer_type = TREE_TYPE (arg1_unw);
- min = lower_bound_in_type (outer_type, shorter_type);
- max = upper_bound_in_type (outer_type, shorter_type);
-
- above = integer_nonzerop (fold_relational_const (LT_EXPR, type,
- max, arg1_unw));
- below = integer_nonzerop (fold_relational_const (LT_EXPR, type,
- arg1_unw, min));
-
- switch (code)
- {
- case EQ_EXPR:
- if (above || below)
- return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
- break;
-
- case NE_EXPR:
- if (above || below)
- return omit_one_operand_loc (loc, type, integer_one_node, arg0);
- break;
-
- case LT_EXPR:
- case LE_EXPR:
- if (above)
- return omit_one_operand_loc (loc, type, integer_one_node, arg0);
- else if (below)
- return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
-
- case GT_EXPR:
- case GE_EXPR:
- if (above)
- return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
- else if (below)
- return omit_one_operand_loc (loc, type, integer_one_node, arg0);
-
- default:
- break;
- }
-
- return NULL_TREE;
-}
-
-/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where for
- ARG0 just the signedness is changed. */
-
-static tree
-fold_sign_changed_comparison (location_t loc, enum tree_code code, tree type,
- tree arg0, tree arg1)
-{
- tree arg0_inner;
- tree inner_type, outer_type;
-
- if (!CONVERT_EXPR_P (arg0))
- 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
- && !(CONVERT_EXPR_P (arg1)
- && TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type))
- return NULL_TREE;
-
- if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
- && code != NE_EXPR
- && code != EQ_EXPR)
- return NULL_TREE;
-
- if (POINTER_TYPE_P (inner_type) != POINTER_TYPE_P (outer_type))
- return NULL_TREE;
-
- if (TREE_CODE (arg1) == INTEGER_CST)
- arg1 = force_fit_type (inner_type, wi::to_widest (arg1), 0,
- TREE_OVERFLOW (arg1));
- else
- arg1 = fold_convert_loc (loc, inner_type, arg1);
-
- return fold_build2_loc (loc, code, type, arg0_inner, arg1);
-}
-
/* Fold A < X && A + 1 > Y to A < X && A >= Y. Normally A + 1 > Y
means A >= Y && A != MAX, but in this case we know that
int
native_encode_expr (const_tree expr, unsigned char *ptr, int len, int off)
{
+ /* We don't support starting at negative offset and -1 is special. */
+ if (off < -1)
+ return 0;
+
switch (TREE_CODE (expr))
{
case INTEGER_CST:
{
machine_mode mode = TYPE_MODE (type);
int total_bytes = GET_MODE_SIZE (mode);
- int byte, offset, word, words, bitpos;
unsigned char value;
/* There are always 32 bits in each long, no matter the size of
the hosts long. We handle floating point representations with
total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
if (total_bytes > len || total_bytes > 24)
return NULL_TREE;
- words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD;
+ int words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD;
memset (tmp, 0, sizeof (tmp));
- for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT;
+ for (int bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT;
bitpos += BITS_PER_UNIT)
{
- byte = (bitpos / BITS_PER_UNIT) & 3;
+ /* Both OFFSET and BYTE index within a long;
+ bitpos indexes the whole float. */
+ int offset, byte = (bitpos / BITS_PER_UNIT) & 3;
if (UNITS_PER_WORD < 4)
{
- word = byte / UNITS_PER_WORD;
+ int word = byte / UNITS_PER_WORD;
if (WORDS_BIG_ENDIAN)
word = (words - 1) - word;
offset = word * UNITS_PER_WORD;
offset += byte % UNITS_PER_WORD;
}
else
- offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
+ {
+ offset = byte;
+ if (BYTES_BIG_ENDIAN)
+ {
+ /* Reverse bytes within each long, or within the entire float
+ if it's smaller than a long (for HFmode). */
+ offset = MIN (3, total_bytes - 1) - offset;
+ gcc_assert (offset >= 0);
+ }
+ }
value = ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)];
tmp[bitpos / 32] |= (unsigned long)value << (bitpos & 31);
cst &= HOST_WIDE_INT_M1U
<< (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)))
and0 = fold_convert_loc (loc, uns, and0);
and1 = fold_convert_loc (loc, uns, and1);
}
-#endif
}
if (change)
{
TREE_TYPE (targ0),
targ0));
}
- /* ABS_EXPR<ABS_EXPR<x>> = ABS_EXPR<x> even if flag_wrapv is on. */
- else if (TREE_CODE (arg0) == ABS_EXPR)
- return arg0;
-
- /* Strip sign ops from argument. */
- if (TREE_CODE (type) == REAL_TYPE)
- {
- tem = fold_strip_sign_ops (arg0);
- if (tem)
- return fold_build1_loc (loc, ABS_EXPR, type,
- fold_convert_loc (loc, type, tem));
- }
- return NULL_TREE;
-
- case CONJ_EXPR:
- if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
- return fold_convert_loc (loc, type, arg0);
- if (TREE_CODE (arg0) == COMPLEX_EXPR)
- {
- tree itype = TREE_TYPE (type);
- tree rpart = fold_convert_loc (loc, itype, TREE_OPERAND (arg0, 0));
- tree ipart = fold_convert_loc (loc, itype, TREE_OPERAND (arg0, 1));
- return fold_build2_loc (loc, COMPLEX_EXPR, type, rpart,
- negate_expr (ipart));
- }
- if (TREE_CODE (arg0) == CONJ_EXPR)
- return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
- return NULL_TREE;
+ return NULL_TREE;
case BIT_NOT_EXPR:
- /* Convert ~ (-A) to A - 1. */
- if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
- return fold_build2_loc (loc, MINUS_EXPR, type,
- fold_convert_loc (loc, 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)))))
- {
- /* Perform the negation in ARG0's type and only then convert
- to TYPE as to avoid introducing undefined behavior. */
- tree t = fold_build1_loc (loc, NEGATE_EXPR,
- TREE_TYPE (TREE_OPERAND (arg0, 0)),
- TREE_OPERAND (arg0, 0));
- return fold_convert_loc (loc, type, t);
- }
/* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify. */
- else if (TREE_CODE (arg0) == BIT_XOR_EXPR
- && (tem = fold_unary_loc (loc, BIT_NOT_EXPR, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 0)))))
+ if (TREE_CODE (arg0) == BIT_XOR_EXPR
+ && (tem = fold_unary_loc (loc, BIT_NOT_EXPR, type,
+ fold_convert_loc (loc, type,
+ TREE_OPERAND (arg0, 0)))))
return fold_build2_loc (loc, BIT_XOR_EXPR, type, tem,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 1)));
+ fold_convert_loc (loc, type,
+ TREE_OPERAND (arg0, 1)));
else if (TREE_CODE (arg0) == BIT_XOR_EXPR
&& (tem = fold_unary_loc (loc, BIT_NOT_EXPR, type,
fold_convert_loc (loc, type,
return NULL_TREE;
return fold_convert_loc (loc, type, tem);
- case REALPART_EXPR:
- if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
- return fold_convert_loc (loc, type, arg0);
- if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
- {
- tree itype = TREE_TYPE (TREE_TYPE (arg0));
- tem = fold_build2_loc (loc, TREE_CODE (arg0), itype,
- fold_build1_loc (loc, REALPART_EXPR, itype,
- TREE_OPERAND (arg0, 0)),
- fold_build1_loc (loc, REALPART_EXPR, itype,
- TREE_OPERAND (arg0, 1)));
- return fold_convert_loc (loc, type, tem);
- }
- if (TREE_CODE (arg0) == CONJ_EXPR)
- {
- tree itype = TREE_TYPE (TREE_TYPE (arg0));
- tem = fold_build1_loc (loc, REALPART_EXPR, itype,
- TREE_OPERAND (arg0, 0));
- return fold_convert_loc (loc, type, tem);
- }
- if (TREE_CODE (arg0) == CALL_EXPR)
- {
- tree fn = get_callee_fndecl (arg0);
- if (fn && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
- switch (DECL_FUNCTION_CODE (fn))
- {
- CASE_FLT_FN (BUILT_IN_CEXPI):
- fn = mathfn_built_in (type, BUILT_IN_COS);
- if (fn)
- return build_call_expr_loc (loc, fn, 1, CALL_EXPR_ARG (arg0, 0));
- break;
-
- default:
- break;
- }
- }
- return NULL_TREE;
-
- case IMAGPART_EXPR:
- if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
- return build_zero_cst (type);
- if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
- {
- tree itype = TREE_TYPE (TREE_TYPE (arg0));
- tem = fold_build2_loc (loc, TREE_CODE (arg0), itype,
- fold_build1_loc (loc, IMAGPART_EXPR, itype,
- TREE_OPERAND (arg0, 0)),
- fold_build1_loc (loc, IMAGPART_EXPR, itype,
- TREE_OPERAND (arg0, 1)));
- return fold_convert_loc (loc, type, tem);
- }
- if (TREE_CODE (arg0) == CONJ_EXPR)
- {
- tree itype = TREE_TYPE (TREE_TYPE (arg0));
- tem = fold_build1_loc (loc, IMAGPART_EXPR, itype, TREE_OPERAND (arg0, 0));
- return fold_convert_loc (loc, type, negate_expr (tem));
- }
- if (TREE_CODE (arg0) == CALL_EXPR)
- {
- tree fn = get_callee_fndecl (arg0);
- if (fn && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
- switch (DECL_FUNCTION_CODE (fn))
- {
- CASE_FLT_FN (BUILT_IN_CEXPI):
- fn = mathfn_built_in (type, BUILT_IN_SIN);
- if (fn)
- return build_call_expr_loc (loc, fn, 1, CALL_EXPR_ARG (arg0, 0));
- break;
-
- default:
- break;
- }
- }
- return NULL_TREE;
-
case INDIRECT_REF:
/* Fold *&X to X if X is an lvalue. */
if (TREE_CODE (op0) == ADDR_EXPR)
enum tree_code code0 = TREE_CODE (arg0);
tree t, cst0 = NULL_TREE;
int sgn0;
- bool swap = false;
-
- /* Match A +- CST code arg1 and CST code arg1. We can change the
- first form only if overflow is undefined. */
- if (!((TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))
- /* In principle pointers also have undefined overflow behavior,
- but that causes problems elsewhere. */
- && !POINTER_TYPE_P (TREE_TYPE (arg0))
- && (code0 == MINUS_EXPR
- || code0 == PLUS_EXPR)
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- || code0 == INTEGER_CST))
+
+ /* Match A +- CST code arg1. We can change this only if overflow
+ is undefined. */
+ if (!((ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))
+ /* In principle pointers also have undefined overflow behavior,
+ but that causes problems elsewhere. */
+ && !POINTER_TYPE_P (TREE_TYPE (arg0))
+ && (code0 == MINUS_EXPR
+ || code0 == PLUS_EXPR)
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST))
return NULL_TREE;
/* Identify the constant in arg0 and its sign. */
- if (code0 == INTEGER_CST)
- cst0 = arg0;
- else
- cst0 = TREE_OPERAND (arg0, 1);
+ cst0 = TREE_OPERAND (arg0, 1);
sgn0 = tree_int_cst_sgn (cst0);
/* Overflowed constants and zero will cause problems. */
/* See if we can reduce the magnitude of the constant in
arg0 by changing the comparison code. */
- if (code0 == INTEGER_CST)
- {
- /* CST <= arg1 -> CST-1 < arg1. */
- if (code == LE_EXPR && sgn0 == 1)
- code = LT_EXPR;
- /* -CST < arg1 -> -CST-1 <= arg1. */
- else if (code == LT_EXPR && sgn0 == -1)
- code = LE_EXPR;
- /* CST > arg1 -> CST-1 >= arg1. */
- else if (code == GT_EXPR && sgn0 == 1)
- code = GE_EXPR;
- /* -CST >= arg1 -> -CST-1 > arg1. */
- else if (code == GE_EXPR && sgn0 == -1)
- code = GT_EXPR;
- else
- return NULL_TREE;
- /* arg1 code' CST' might be more canonical. */
- swap = true;
- }
+ /* A - CST < arg1 -> A - CST-1 <= arg1. */
+ if (code == LT_EXPR
+ && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
+ code = LE_EXPR;
+ /* A + CST > arg1 -> A + CST-1 >= arg1. */
+ else if (code == GT_EXPR
+ && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
+ code = GE_EXPR;
+ /* A + CST <= arg1 -> A + CST-1 < arg1. */
+ else if (code == LE_EXPR
+ && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
+ code = LT_EXPR;
+ /* A - CST >= arg1 -> A - CST-1 > arg1. */
+ else if (code == GE_EXPR
+ && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
+ code = GT_EXPR;
else
- {
- /* A - CST < arg1 -> A - CST-1 <= arg1. */
- if (code == LT_EXPR
- && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
- code = LE_EXPR;
- /* A + CST > arg1 -> A + CST-1 >= arg1. */
- else if (code == GT_EXPR
- && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
- code = GE_EXPR;
- /* A + CST <= arg1 -> A + CST-1 < arg1. */
- else if (code == LE_EXPR
- && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
- code = LT_EXPR;
- /* A - CST >= arg1 -> A - CST-1 > arg1. */
- else if (code == GE_EXPR
- && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
- code = GT_EXPR;
- else
- return NULL_TREE;
- *strict_overflow_p = true;
- }
+ return NULL_TREE;
+ *strict_overflow_p = true;
/* Now build the constant reduced in magnitude. But not if that
would produce one outside of its types range. */
|| (sgn0 == -1
&& TYPE_MAX_VALUE (TREE_TYPE (cst0))
&& tree_int_cst_equal (cst0, TYPE_MAX_VALUE (TREE_TYPE (cst0))))))
- /* We cannot swap the comparison here as that would cause us to
- endlessly recurse. */
return NULL_TREE;
t = int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR,
cst0, build_int_cst (TREE_TYPE (cst0), 1));
- if (code0 != INTEGER_CST)
- t = fold_build2_loc (loc, code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t);
+ t = fold_build2_loc (loc, code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t);
t = fold_convert (TREE_TYPE (arg1), t);
- /* If swapping might yield to a more canonical form, do so. */
- if (swap)
- return fold_build2_loc (loc, swap_tree_comparison (code), type, arg1, t);
- else
- return fold_build2_loc (loc, code, type, t, arg1);
+ return fold_build2_loc (loc, code, type, t, arg1);
}
/* Canonicalize the comparison ARG0 CODE ARG1 with type TYPE with undefined
/* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 -+ C1. */
if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
- && (equality_code || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))
+ && (equality_code
+ || (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))))
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
&& !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
&& TREE_CODE (arg1) == INTEGER_CST
}
}
- /* Transform comparisons of the form X - Y CMP 0 to X CMP Y. */
- if (TREE_CODE (arg0) == MINUS_EXPR
- && equality_code
- && integer_zerop (arg1))
- {
- /* ??? The transformation is valid for the other operators if overflow
- is undefined for the type, but performing it here badly interacts
- with the transformation in fold_cond_expr_with_comparison which
- attempts to synthetize ABS_EXPR. */
- if (!equality_code)
- fold_overflow_warning ("assuming signed overflow does not occur "
- "when changing X - Y cmp 0 to X cmp Y",
- WARN_STRICT_OVERFLOW_COMPARISON);
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg0, 1));
- }
-
/* For comparisons of pointers we can decompose it to a compile time
comparison of the base objects and the offsets into the object.
This requires at least one operand being an ADDR_EXPR or a
}
}
- /* A local variable can never be pointed to by
- the default SSA name of an incoming parameter. */
- if ((TREE_CODE (arg0) == ADDR_EXPR
- && indirect_base0
- && TREE_CODE (base0) == VAR_DECL
- && auto_var_in_fn_p (base0, current_function_decl)
- && !indirect_base1
- && TREE_CODE (base1) == SSA_NAME
- && SSA_NAME_IS_DEFAULT_DEF (base1)
- && TREE_CODE (SSA_NAME_VAR (base1)) == PARM_DECL)
- || (TREE_CODE (arg1) == ADDR_EXPR
- && indirect_base1
- && TREE_CODE (base1) == VAR_DECL
- && auto_var_in_fn_p (base1, current_function_decl)
- && !indirect_base0
- && TREE_CODE (base0) == SSA_NAME
- && SSA_NAME_IS_DEFAULT_DEF (base0)
- && TREE_CODE (SSA_NAME_VAR (base0)) == PARM_DECL))
- {
- if (code == NE_EXPR)
- return constant_boolean_node (1, type);
- else if (code == EQ_EXPR)
- return constant_boolean_node (0, type);
- }
/* If we have equivalent bases we might be able to simplify. */
- else if (indirect_base0 == indirect_base1
- && operand_equal_p (base0, base1, 0))
+ if (indirect_base0 == indirect_base1
+ && operand_equal_p (base0, base1,
+ indirect_base0 ? OEP_ADDRESS_OF : 0))
{
/* We can fold this expression to a constant if the non-constant
offset parts are equal. */
return fold_build2_loc (loc, code, type, offset0, offset1);
}
}
- /* For non-equal bases we can simplify if they are addresses
- declarations with different addresses. */
- else if (indirect_base0 && indirect_base1
- /* We know that !operand_equal_p (base0, base1, 0)
- because the if condition was false. But make
- sure two decls are not the same. */
- && base0 != base1
- && TREE_CODE (arg0) == ADDR_EXPR
- && TREE_CODE (arg1) == ADDR_EXPR
- && DECL_P (base0)
- && DECL_P (base1)
- /* Watch for aliases. */
- && (!decl_in_symtab_p (base0)
- || !decl_in_symtab_p (base1)
- || !symtab_node::get_create (base0)->equal_address_to
- (symtab_node::get_create (base1))))
- {
- if (code == EQ_EXPR)
- return omit_two_operands_loc (loc, type, boolean_false_node,
- arg0, arg1);
- else if (code == NE_EXPR)
- return omit_two_operands_loc (loc, type, boolean_true_node,
- arg0, arg1);
- }
/* For equal offsets we can simplify to a comparison of the
base addresses. */
else if (bitpos0 == bitpos1
X CMP Y +- C2 +- C1 for signed X, Y. This is valid if
the resulting offset is smaller in absolute value than the
original one and has the same sign. */
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))
+ if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))
&& (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
&& (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
&& !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)))
}
}
- /* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the
- signed arithmetic case. That form is created by the compiler
- often enough for folding it to be of value. One example is in
- computing loop trip counts after Operator Strength Reduction. */
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))
- && TREE_CODE (arg0) == MULT_EXPR
- && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)))
- && integer_zerop (arg1))
- {
- tree const1 = TREE_OPERAND (arg0, 1);
- tree const2 = arg1; /* zero */
- tree variable1 = TREE_OPERAND (arg0, 0);
- enum tree_code cmp_code = code;
-
- /* Handle unfolded multiplication by zero. */
- if (integer_zerop (const1))
- return fold_build2_loc (loc, cmp_code, type, const1, const2);
-
- fold_overflow_warning (("assuming signed overflow does not occur when "
- "eliminating multiplication in comparison "
- "with zero"),
- WARN_STRICT_OVERFLOW_COMPARISON);
-
- /* If const1 is negative we swap the sense of the comparison. */
- if (tree_int_cst_sgn (const1) < 0)
- cmp_code = swap_tree_comparison (cmp_code);
-
- return fold_build2_loc (loc, cmp_code, type, variable1, const2);
- }
-
tem = maybe_canonicalize_comparison (loc, code, type, arg0, arg1);
if (tem)
return tem;
- if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
- {
- tree targ0 = strip_float_extensions (arg0);
- tree targ1 = strip_float_extensions (arg1);
- tree newtype = TREE_TYPE (targ0);
-
- if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
- newtype = TREE_TYPE (targ1);
-
- /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */
- if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
- return fold_build2_loc (loc, code, type,
- fold_convert_loc (loc, newtype, targ0),
- fold_convert_loc (loc, newtype, targ1));
-
- /* (-a) CMP (-b) -> b CMP a */
- if (TREE_CODE (arg0) == NEGATE_EXPR
- && TREE_CODE (arg1) == NEGATE_EXPR)
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg1, 0),
- TREE_OPERAND (arg0, 0));
-
- if (TREE_CODE (arg1) == REAL_CST)
- {
- REAL_VALUE_TYPE cst;
- cst = TREE_REAL_CST (arg1);
-
- /* (-a) CMP CST -> a swap(CMP) (-CST) */
- if (TREE_CODE (arg0) == NEGATE_EXPR)
- return fold_build2_loc (loc, swap_tree_comparison (code), type,
- TREE_OPERAND (arg0, 0),
- build_real (TREE_TYPE (arg1),
- real_value_negate (&cst)));
-
- /* IEEE doesn't distinguish +0 and -0 in comparisons. */
- /* a CMP (-0) -> a CMP 0 */
- if (REAL_VALUE_MINUS_ZERO (cst))
- return fold_build2_loc (loc, code, type, arg0,
- build_real (TREE_TYPE (arg1), dconst0));
-
- /* x != NaN is always true, other ops are always false. */
- if (REAL_VALUE_ISNAN (cst)
- && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
- {
- tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
- return omit_one_operand_loc (loc, type, tem, arg0);
- }
-
- /* Fold comparisons against infinity. */
- if (REAL_VALUE_ISINF (cst)
- && MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1))))
- {
- tem = fold_inf_compare (loc, code, type, arg0, arg1);
- if (tem != NULL_TREE)
- return tem;
- }
- }
-
- /* If this is a comparison of a real constant with a PLUS_EXPR
- or a MINUS_EXPR of a real constant, we can convert it into a
- comparison with a revised real constant as long as no overflow
- occurs when unsafe_math_optimizations are enabled. */
- if (flag_unsafe_math_optimizations
- && TREE_CODE (arg1) == REAL_CST
- && (TREE_CODE (arg0) == PLUS_EXPR
- || TREE_CODE (arg0) == MINUS_EXPR)
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
- && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
- ? MINUS_EXPR : PLUS_EXPR,
- arg1, TREE_OPERAND (arg0, 1)))
- && !TREE_OVERFLOW (tem))
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem);
-
- /* Likewise, we can simplify a comparison of a real constant with
- a MINUS_EXPR whose first operand is also a real constant, i.e.
- (c1 - x) < c2 becomes x > c1-c2. Reordering is allowed on
- floating-point types only if -fassociative-math is set. */
- if (flag_associative_math
- && TREE_CODE (arg1) == REAL_CST
- && TREE_CODE (arg0) == MINUS_EXPR
- && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
- && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
- arg1))
- && !TREE_OVERFLOW (tem))
- return fold_build2_loc (loc, swap_tree_comparison (code), type,
- TREE_OPERAND (arg0, 1), tem);
-
- /* Fold comparisons against built-in math functions. */
- if (TREE_CODE (arg1) == REAL_CST
- && flag_unsafe_math_optimizations
- && ! flag_errno_math)
- {
- enum built_in_function fcode = builtin_mathfn_code (arg0);
-
- if (fcode != END_BUILTINS)
- {
- tem = fold_mathfn_compare (loc, fcode, code, type, arg0, arg1);
- if (tem != NULL_TREE)
- return tem;
- }
- }
- }
-
- if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
- && CONVERT_EXPR_P (arg0))
- {
- /* If we are widening one operand of an integer comparison,
- see if the other operand is similarly being widened. Perhaps we
- can do the comparison in the narrower type. */
- tem = fold_widened_comparison (loc, code, type, arg0, arg1);
- if (tem)
- return tem;
-
- /* Or if we are changing signedness. */
- tem = fold_sign_changed_comparison (loc, code, type, arg0, arg1);
- if (tem)
- return tem;
- }
-
/* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a
constant, we can simplify it. */
if (TREE_CODE (arg1) == INTEGER_CST
return tem;
}
- /* Simplify comparison of something with itself. (For IEEE
- floating-point, we can only do some of these simplifications.) */
- if (operand_equal_p (arg0, arg1, 0))
- {
- switch (code)
- {
- case EQ_EXPR:
- if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
- || ! HONOR_NANS (element_mode (arg0)))
- return constant_boolean_node (1, type);
- break;
-
- case GE_EXPR:
- case LE_EXPR:
- if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
- || ! HONOR_NANS (element_mode (arg0)))
- return constant_boolean_node (1, type);
- return fold_build2_loc (loc, EQ_EXPR, type, arg0, arg1);
-
- case NE_EXPR:
- /* For NE, we can only do this simplification if integer
- or we don't honor IEEE floating point NaNs. */
- if (FLOAT_TYPE_P (TREE_TYPE (arg0))
- && HONOR_NANS (element_mode (arg0)))
- break;
- /* ... fall through ... */
- case GT_EXPR:
- case LT_EXPR:
- return constant_boolean_node (0, type);
- default:
- gcc_unreachable ();
- }
- }
-
/* If we are comparing an expression that just has comparisons
of two integer values, arithmetic expressions of those comparisons,
and constants, we can simplify it. There are only three cases
return tem;
}
- /* Fold ~X op ~Y as Y op X. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && TREE_CODE (arg1) == BIT_NOT_EXPR)
- {
- tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
- return fold_build2_loc (loc, code, type,
- fold_convert_loc (loc, cmp_type,
- TREE_OPERAND (arg1, 0)),
- TREE_OPERAND (arg0, 0));
- }
-
- /* Fold ~X op C as X op' ~C, where op' is the swapped comparison. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && (TREE_CODE (arg1) == INTEGER_CST || TREE_CODE (arg1) == VECTOR_CST))
- {
- tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
- return fold_build2_loc (loc, swap_tree_comparison (code), type,
- TREE_OPERAND (arg0, 0),
- fold_build1_loc (loc, BIT_NOT_EXPR, cmp_type,
- fold_convert_loc (loc, cmp_type, arg1)));
- }
-
return NULL_TREE;
}
}
-/* Subroutine of fold_binary. If P is the value of EXPR, computes
- power-of-two M and (arbitrary) N such that M divides (P-N). This condition
- guarantees that P and N have the same least significant log2(M) bits.
- N is not otherwise constrained. In particular, N is not normalized to
- 0 <= N < M as is common. In general, the precise value of P is unknown.
- M is chosen as large as possible such that constant N can be determined.
-
- Returns M and sets *RESIDUE to N.
-
- If ALLOW_FUNC_ALIGN is true, do take functions' DECL_ALIGN_UNIT into
- account. This is not always possible due to PR 35705.
- */
-
-static unsigned HOST_WIDE_INT
-get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue,
- bool allow_func_align)
-{
- enum tree_code code;
-
- *residue = 0;
-
- code = TREE_CODE (expr);
- if (code == ADDR_EXPR)
- {
- unsigned int bitalign;
- get_object_alignment_1 (TREE_OPERAND (expr, 0), &bitalign, residue);
- *residue /= BITS_PER_UNIT;
- return bitalign / BITS_PER_UNIT;
- }
- else if (code == POINTER_PLUS_EXPR)
- {
- tree op0, op1;
- unsigned HOST_WIDE_INT modulus;
- enum tree_code inner_code;
-
- op0 = TREE_OPERAND (expr, 0);
- STRIP_NOPS (op0);
- modulus = get_pointer_modulus_and_residue (op0, residue,
- allow_func_align);
-
- op1 = TREE_OPERAND (expr, 1);
- STRIP_NOPS (op1);
- inner_code = TREE_CODE (op1);
- if (inner_code == INTEGER_CST)
- {
- *residue += TREE_INT_CST_LOW (op1);
- return modulus;
- }
- else if (inner_code == MULT_EXPR)
- {
- op1 = TREE_OPERAND (op1, 1);
- if (TREE_CODE (op1) == INTEGER_CST)
- {
- unsigned HOST_WIDE_INT align;
-
- /* Compute the greatest power-of-2 divisor of op1. */
- align = TREE_INT_CST_LOW (op1);
- align &= -align;
-
- /* If align is non-zero and less than *modulus, replace
- *modulus with align., If align is 0, then either op1 is 0
- or the greatest power-of-2 divisor of op1 doesn't fit in an
- unsigned HOST_WIDE_INT. In either case, no additional
- constraint is imposed. */
- if (align)
- modulus = MIN (modulus, align);
-
- return modulus;
- }
- }
- }
-
- /* If we get here, we were unable to determine anything useful about the
- expression. */
- return 1;
-}
-
/* Helper function for fold_vec_perm. Store elements of VECTOR_CST or
CONSTRUCTOR ARG into array ELTS and return true if successful. */
= fold_addr_of_array_ref_difference (loc, type, base0, base1)))
|| (INDIRECT_REF_P (base0)
&& INDIRECT_REF_P (base1)
- && (base_offset = fold_binary_loc (loc, MINUS_EXPR, type,
- TREE_OPERAND (base0, 0),
- TREE_OPERAND (base1, 0))))
- || operand_equal_p (base0, base1, 0))
+ && (base_offset
+ = fold_binary_loc (loc, MINUS_EXPR, type,
+ fold_convert (type, TREE_OPERAND (base0, 0)),
+ fold_convert (type,
+ TREE_OPERAND (base1, 0)))))
+ || operand_equal_p (base0, base1, OEP_ADDRESS_OF))
{
tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
if (! FLOAT_TYPE_P (type))
{
- /* If we are adding two BIT_AND_EXPR's, both of which are and'ing
- with a constant, and the two constants have no bits in common,
- we should treat this as a BIT_IOR_EXPR since this may produce more
- simplifications. */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && TREE_CODE (arg1) == BIT_AND_EXPR
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
- && wi::bit_and (TREE_OPERAND (arg0, 1),
- TREE_OPERAND (arg1, 1)) == 0)
- {
- code = BIT_IOR_EXPR;
- goto bit_ior;
- }
-
/* Reassociate (plus (plus (mult) (foo)) (mult)) as
(plus (plus (mult) (mult)) (foo)) so that we can
take advantage of the factoring cases below. */
- if (TYPE_OVERFLOW_WRAPS (type)
+ if (ANY_INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_WRAPS (type)
&& (((TREE_CODE (arg0) == PLUS_EXPR
|| TREE_CODE (arg0) == MINUS_EXPR)
&& TREE_CODE (arg1) == MULT_EXPR)
/* Only create rotates in complete modes. Other cases are not
expanded properly. */
&& (element_precision (rtype)
- == element_precision (TYPE_MODE (rtype))))
+ == GET_MODE_UNIT_PRECISION (TYPE_MODE (rtype))))
{
tree tree01, tree11;
enum tree_code code01, code11;
tem = build2_loc (loc, LROTATE_EXPR,
TREE_TYPE (TREE_OPERAND (arg0, 0)),
TREE_OPERAND (arg0, 0),
- code0 == LSHIFT_EXPR ? tree01 : tree11);
+ code0 == LSHIFT_EXPR
+ ? TREE_OPERAND (arg0, 1)
+ : TREE_OPERAND (arg1, 1));
return fold_convert_loc (loc, type, tem);
}
else if (code11 == MINUS_EXPR)
? LROTATE_EXPR
: RROTATE_EXPR),
TREE_TYPE (TREE_OPERAND (arg0, 0)),
- TREE_OPERAND (arg0, 0), tree01));
+ TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1)));
}
else if (code01 == MINUS_EXPR)
{
? LROTATE_EXPR
: RROTATE_EXPR),
TREE_TYPE (TREE_OPERAND (arg0, 0)),
- TREE_OPERAND (arg0, 0), tree11));
+ TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 1)));
}
}
}
{
tree tmp0 = var0;
tree tmp1 = var1;
+ bool one_neg = false;
if (TREE_CODE (tmp0) == NEGATE_EXPR)
- tmp0 = TREE_OPERAND (tmp0, 0);
+ {
+ tmp0 = TREE_OPERAND (tmp0, 0);
+ one_neg = !one_neg;
+ }
if (CONVERT_EXPR_P (tmp0)
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp0, 0)))
&& (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp0, 0)))
<= TYPE_PRECISION (atype)))
tmp0 = TREE_OPERAND (tmp0, 0);
if (TREE_CODE (tmp1) == NEGATE_EXPR)
- tmp1 = TREE_OPERAND (tmp1, 0);
+ {
+ tmp1 = TREE_OPERAND (tmp1, 0);
+ one_neg = !one_neg;
+ }
if (CONVERT_EXPR_P (tmp1)
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp1, 0)))
&& (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp1, 0)))
<= TYPE_PRECISION (atype)))
tmp1 = TREE_OPERAND (tmp1, 0);
/* The only case we can still associate with two variables
- is if they are the same, modulo negation and bit-pattern
- preserving conversions. */
- if (!operand_equal_p (tmp0, tmp1, 0))
+ is if they cancel out. */
+ if (!one_neg
+ || !operand_equal_p (tmp0, tmp1, 0))
ok = false;
}
}
return NULL_TREE;
case MINUS_EXPR:
- /* Pointer simplifications for subtraction, simple reassociations. */
- if (POINTER_TYPE_P (TREE_TYPE (arg1)) && POINTER_TYPE_P (TREE_TYPE (arg0)))
- {
- /* (PTR0 p+ A) - (PTR1 p+ B) -> (PTR0 - PTR1) + (A - B) */
- if (TREE_CODE (arg0) == POINTER_PLUS_EXPR
- && TREE_CODE (arg1) == POINTER_PLUS_EXPR)
- {
- tree arg00 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
- tree arg01 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
- tree arg10 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0));
- tree arg11 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1));
- return fold_build2_loc (loc, PLUS_EXPR, type,
- fold_build2_loc (loc, MINUS_EXPR, type,
- arg00, arg10),
- fold_build2_loc (loc, MINUS_EXPR, type,
- arg01, arg11));
- }
- /* (PTR0 p+ A) - PTR1 -> (PTR0 - PTR1) + A, assuming PTR0 - PTR1 simplifies. */
- else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
- {
- tree arg00 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
- tree arg01 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
- tree tmp = fold_binary_loc (loc, MINUS_EXPR, type, arg00,
- fold_convert_loc (loc, type, arg1));
- if (tmp)
- return fold_build2_loc (loc, PLUS_EXPR, type, tmp, arg01);
- }
- /* PTR0 - (PTR1 p+ A) -> (PTR0 - PTR1) - A, assuming PTR0 - PTR1
- simplifies. */
- else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR)
- {
- tree arg10 = fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 0));
- tree arg11 = fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 1));
- tree tmp = fold_binary_loc (loc, MINUS_EXPR, type,
- fold_convert_loc (loc, type, arg0),
- arg10);
- if (tmp)
- return fold_build2_loc (loc, MINUS_EXPR, type, tmp, arg11);
- }
- }
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
if (TREE_CODE (arg0) == NEGATE_EXPR
&& negate_expr_p (arg1)
fold_convert_loc (loc, type,
TREE_OPERAND (arg0, 0)));
- /* X - (X / Y) * Y is X % Y. */
- if ((INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
- && TREE_CODE (arg1) == MULT_EXPR
- && TREE_CODE (TREE_OPERAND (arg1, 0)) == TRUNC_DIV_EXPR
- && operand_equal_p (arg0,
- TREE_OPERAND (TREE_OPERAND (arg1, 0), 0), 0)
- && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg1, 0), 1),
- TREE_OPERAND (arg1, 1), 0))
- return
- fold_convert_loc (loc, type,
- fold_build2_loc (loc, TRUNC_MOD_EXPR, TREE_TYPE (arg0),
- arg0, TREE_OPERAND (arg1, 1)));
-
- if (! FLOAT_TYPE_P (type))
- {
- /* Fold A - (A & B) into ~B & A. */
- if (!TREE_SIDE_EFFECTS (arg0)
- && TREE_CODE (arg1) == BIT_AND_EXPR)
- {
- if (operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0))
- {
- tree arg10 = fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 0));
- return fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_build1_loc (loc, BIT_NOT_EXPR,
- type, arg10),
- fold_convert_loc (loc, type, arg0));
- }
- if (operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
- {
- tree arg11 = fold_convert_loc (loc,
- type, TREE_OPERAND (arg1, 1));
- return fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_build1_loc (loc, BIT_NOT_EXPR,
- type, arg11),
- fold_convert_loc (loc, type, arg0));
- }
- }
-
- /* Fold (A & ~B) - (A & B) into (A ^ B) - B, where B is
- any power of 2 minus 1. */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && TREE_CODE (arg1) == BIT_AND_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg1, 0), 0))
- {
- tree mask0 = TREE_OPERAND (arg0, 1);
- tree mask1 = TREE_OPERAND (arg1, 1);
- tree tem = fold_build1_loc (loc, BIT_NOT_EXPR, type, mask0);
-
- if (operand_equal_p (tem, mask1, 0))
- {
- tem = fold_build2_loc (loc, BIT_XOR_EXPR, type,
- TREE_OPERAND (arg0, 0), mask1);
- return fold_build2_loc (loc, MINUS_EXPR, type, tem, mask1);
- }
- }
- }
-
/* Fold __complex__ ( x, 0 ) - __complex__ ( 0, y ) to
__complex__ ( x, -y ). This is not the same for SNaNs or if
signed zeros are involved. */
fold_convert_loc (loc, type,
negate_expr (arg1)));
- /* Try folding difference of addresses. */
- {
- HOST_WIDE_INT diff;
-
- if ((TREE_CODE (arg0) == ADDR_EXPR
- || TREE_CODE (arg1) == ADDR_EXPR)
- && ptr_difference_const (arg0, arg1, &diff))
- return build_int_cst_type (type, diff);
- }
-
/* Fold &a[i] - &a[j] to i-j. */
if (TREE_CODE (arg0) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF
goto associate;
case MULT_EXPR:
- /* (-A) * (-B) -> A * B */
- if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
- return fold_build2_loc (loc, MULT_EXPR, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 0)),
- fold_convert_loc (loc, type,
- negate_expr (arg1)));
- if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
- return fold_build2_loc (loc, MULT_EXPR, type,
- fold_convert_loc (loc, type,
- negate_expr (arg0)),
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 0)));
-
if (! FLOAT_TYPE_P (type))
{
/* Transform x * -C into -x * C if x is easily negatable. */
negate_expr (arg0)),
tem);
- /* (a * (1 << b)) is (a << b) */
- if (TREE_CODE (arg1) == LSHIFT_EXPR
- && integer_onep (TREE_OPERAND (arg1, 0)))
- return fold_build2_loc (loc, LSHIFT_EXPR, type, op0,
- TREE_OPERAND (arg1, 1));
- if (TREE_CODE (arg0) == LSHIFT_EXPR
- && integer_onep (TREE_OPERAND (arg0, 0)))
- return fold_build2_loc (loc, LSHIFT_EXPR, type, op1,
- TREE_OPERAND (arg0, 1));
-
/* (A + A) * C -> A * 2 * C */
if (TREE_CODE (arg0) == PLUS_EXPR
&& TREE_CODE (arg1) == INTEGER_CST
}
else
{
- /* Convert (C1/X)*C2 into (C1*C2)/X. This transformation may change
- the result for floating point types due to rounding so it is applied
- only if -fassociative-math was specify. */
- if (flag_associative_math
- && TREE_CODE (arg0) == RDIV_EXPR
- && TREE_CODE (arg1) == REAL_CST
- && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST)
- {
- tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0),
- arg1);
- if (tem)
- return fold_build2_loc (loc, RDIV_EXPR, type, tem,
- TREE_OPERAND (arg0, 1));
- }
-
- /* Strip sign operations from X in X*X, i.e. -Y*-Y -> Y*Y. */
- if (operand_equal_p (arg0, arg1, 0))
- {
- tree tem = fold_strip_sign_ops (arg0);
- if (tem != NULL_TREE)
- {
- tem = fold_convert_loc (loc, type, tem);
- return fold_build2_loc (loc, MULT_EXPR, type, tem, tem);
- }
- }
-
/* Fold z * +-I to __complex__ (-+__imag z, +-__real z).
This is not the same for NaNs or if signed zeros are
involved. */
- if (!HONOR_NANS (element_mode (arg0))
+ if (!HONOR_NANS (arg0)
&& !HONOR_SIGNED_ZEROS (element_mode (arg0))
&& COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0))
&& TREE_CODE (arg1) == COMPLEX_CST
if (flag_unsafe_math_optimizations)
{
- enum built_in_function fcode0 = builtin_mathfn_code (arg0);
- enum built_in_function fcode1 = builtin_mathfn_code (arg1);
-
- /* Optimizations of root(...)*root(...). */
- if (fcode0 == fcode1 && BUILTIN_ROOT_P (fcode0))
- {
- tree rootfn, arg;
- tree arg00 = CALL_EXPR_ARG (arg0, 0);
- tree arg10 = CALL_EXPR_ARG (arg1, 0);
-
- /* Optimize sqrt(x)*sqrt(x) as x. */
- if (BUILTIN_SQRT_P (fcode0)
- && operand_equal_p (arg00, arg10, 0)
- && ! HONOR_SNANS (element_mode (type)))
- return arg00;
-
- /* Optimize root(x)*root(y) as root(x*y). */
- rootfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
- arg = fold_build2_loc (loc, MULT_EXPR, type, arg00, arg10);
- return build_call_expr_loc (loc, rootfn, 1, arg);
- }
-
- /* Optimize expN(x)*expN(y) as expN(x+y). */
- if (fcode0 == fcode1 && BUILTIN_EXPONENT_P (fcode0))
- {
- tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
- tree arg = fold_build2_loc (loc, PLUS_EXPR, type,
- CALL_EXPR_ARG (arg0, 0),
- CALL_EXPR_ARG (arg1, 0));
- return build_call_expr_loc (loc, expfn, 1, arg);
- }
-
- /* Optimizations of pow(...)*pow(...). */
- if ((fcode0 == BUILT_IN_POW && fcode1 == BUILT_IN_POW)
- || (fcode0 == BUILT_IN_POWF && fcode1 == BUILT_IN_POWF)
- || (fcode0 == BUILT_IN_POWL && fcode1 == BUILT_IN_POWL))
- {
- tree arg00 = CALL_EXPR_ARG (arg0, 0);
- tree arg01 = CALL_EXPR_ARG (arg0, 1);
- tree arg10 = CALL_EXPR_ARG (arg1, 0);
- tree arg11 = CALL_EXPR_ARG (arg1, 1);
-
- /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y). */
- if (operand_equal_p (arg01, arg11, 0))
- {
- tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
- tree arg = fold_build2_loc (loc, MULT_EXPR, type,
- arg00, arg10);
- return build_call_expr_loc (loc, powfn, 2, arg, arg01);
- }
- /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z). */
- if (operand_equal_p (arg00, arg10, 0))
- {
- tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
- tree arg = fold_build2_loc (loc, PLUS_EXPR, type,
- arg01, arg11);
- return build_call_expr_loc (loc, powfn, 2, arg00, arg);
- }
- }
-
- /* Optimize tan(x)*cos(x) as sin(x). */
- if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_COS)
- || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_COSF)
- || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_COSL)
- || (fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_TAN)
- || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_TANF)
- || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_TANL))
- && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
- CALL_EXPR_ARG (arg1, 0), 0))
+ /* Canonicalize x*x as pow(x,2.0), which is expanded as x*x. */
+ if (!in_gimple_form
+ && optimize
+ && operand_equal_p (arg0, arg1, 0))
{
- tree sinfn = mathfn_built_in (type, BUILT_IN_SIN);
-
- if (sinfn != NULL_TREE)
- return build_call_expr_loc (loc, sinfn, 1,
- CALL_EXPR_ARG (arg0, 0));
- }
+ tree powfn = mathfn_built_in (type, BUILT_IN_POW);
- /* Optimize x*pow(x,c) as pow(x,c+1). */
- if (fcode1 == BUILT_IN_POW
- || fcode1 == BUILT_IN_POWF
- || fcode1 == BUILT_IN_POWL)
- {
- tree arg10 = CALL_EXPR_ARG (arg1, 0);
- tree arg11 = CALL_EXPR_ARG (arg1, 1);
- if (TREE_CODE (arg11) == REAL_CST
- && !TREE_OVERFLOW (arg11)
- && operand_equal_p (arg0, arg10, 0))
+ if (powfn)
{
- tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
- REAL_VALUE_TYPE c;
- tree arg;
-
- c = TREE_REAL_CST (arg11);
- real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
- arg = build_real (type, c);
- return build_call_expr_loc (loc, powfn, 2, arg0, arg);
- }
- }
-
- /* Optimize pow(x,c)*x as pow(x,c+1). */
- if (fcode0 == BUILT_IN_POW
- || fcode0 == BUILT_IN_POWF
- || fcode0 == BUILT_IN_POWL)
- {
- tree arg00 = CALL_EXPR_ARG (arg0, 0);
- tree arg01 = CALL_EXPR_ARG (arg0, 1);
- if (TREE_CODE (arg01) == REAL_CST
- && !TREE_OVERFLOW (arg01)
- && operand_equal_p (arg1, arg00, 0))
- {
- tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
- REAL_VALUE_TYPE c;
- tree arg;
-
- c = TREE_REAL_CST (arg01);
- real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
- arg = build_real (type, c);
- return build_call_expr_loc (loc, powfn, 2, arg1, arg);
- }
- }
-
- /* Canonicalize x*x as pow(x,2.0), which is expanded as x*x. */
- if (!in_gimple_form
- && optimize
- && operand_equal_p (arg0, arg1, 0))
- {
- tree powfn = mathfn_built_in (type, BUILT_IN_POW);
-
- if (powfn)
- {
- tree arg = build_real (type, dconst2);
+ tree arg = build_real (type, dconst2);
return build_call_expr_loc (loc, powfn, 2, arg0, arg);
}
}
goto associate;
case BIT_IOR_EXPR:
- bit_ior:
- /* ~X | X is -1. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
- {
- t1 = build_zero_cst (type);
- t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
- return omit_one_operand_loc (loc, type, t1, arg1);
- }
-
- /* X | ~X is -1. */
- if (TREE_CODE (arg1) == BIT_NOT_EXPR
- && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
- {
- t1 = build_zero_cst (type);
- t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
- return omit_one_operand_loc (loc, type, t1, arg0);
- }
-
/* Canonicalize (X & C1) | C2. */
if (TREE_CODE (arg0) == BIT_AND_EXPR
&& TREE_CODE (arg1) == INTEGER_CST
arg1);
}
- /* (X & ~Y) | (~X & Y) is X ^ Y */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && TREE_CODE (arg1) == BIT_AND_EXPR)
- {
- tree a0, a1, l0, l1, n0, n1;
-
- a0 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0));
- a1 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1));
-
- l0 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
- l1 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
-
- n0 = fold_build1_loc (loc, BIT_NOT_EXPR, type, l0);
- n1 = fold_build1_loc (loc, BIT_NOT_EXPR, type, l1);
-
- if ((operand_equal_p (n0, a0, 0)
- && operand_equal_p (n1, a1, 0))
- || (operand_equal_p (n0, a1, 0)
- && operand_equal_p (n1, a0, 0)))
- return fold_build2_loc (loc, BIT_XOR_EXPR, type, l0, n1);
- }
-
- t1 = distribute_bit_expr (loc, code, type, arg0, arg1);
- if (t1 != NULL_TREE)
- return t1;
-
- /* Convert (or (not arg0) (not arg1)) to (not (and (arg0) (arg1))).
-
- This results in more efficient code for machines without a NAND
- instruction. Combine will canonicalize to the first form
- which will allow use of NAND instructions provided by the
- backend if they exist. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && TREE_CODE (arg1) == BIT_NOT_EXPR)
- {
- return
- fold_build1_loc (loc, BIT_NOT_EXPR, type,
- build2 (BIT_AND_EXPR, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 0)),
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 0))));
- }
-
/* See if this can be simplified into a rotate first. If that
is unsuccessful continue in the association code. */
goto bit_rotate;
case BIT_XOR_EXPR:
- /* ~X ^ X is -1. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
- {
- t1 = build_zero_cst (type);
- t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
- return omit_one_operand_loc (loc, type, t1, arg1);
- }
-
- /* X ^ ~X is -1. */
- if (TREE_CODE (arg1) == BIT_NOT_EXPR
- && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
- {
- t1 = build_zero_cst (type);
- t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
- return omit_one_operand_loc (loc, type, t1, arg0);
- }
-
- /* If we are XORing two BIT_AND_EXPR's, both of which are and'ing
- with a constant, and the two constants have no bits in common,
- we should treat this as a BIT_IOR_EXPR since this may produce more
- simplifications. */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && TREE_CODE (arg1) == BIT_AND_EXPR
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
- && wi::bit_and (TREE_OPERAND (arg0, 1),
- TREE_OPERAND (arg1, 1)) == 0)
- {
- code = BIT_IOR_EXPR;
- goto bit_ior;
- }
-
- /* (X | Y) ^ X -> Y & ~ X*/
- if (TREE_CODE (arg0) == BIT_IOR_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
- {
- tree t2 = TREE_OPERAND (arg0, 1);
- t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg1),
- arg1);
- t1 = fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_convert_loc (loc, type, t2),
- fold_convert_loc (loc, type, t1));
- return t1;
- }
-
- /* (Y | X) ^ X -> Y & ~ X*/
- if (TREE_CODE (arg0) == BIT_IOR_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
- {
- tree t2 = TREE_OPERAND (arg0, 0);
- t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg1),
- arg1);
- t1 = fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_convert_loc (loc, type, t2),
- fold_convert_loc (loc, type, t1));
- return t1;
- }
-
- /* X ^ (X | Y) -> Y & ~ X*/
- if (TREE_CODE (arg1) == BIT_IOR_EXPR
- && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
- {
- tree t2 = TREE_OPERAND (arg1, 1);
- t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg0),
- arg0);
- t1 = fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_convert_loc (loc, type, t2),
- fold_convert_loc (loc, type, t1));
- return t1;
- }
-
- /* X ^ (Y | X) -> Y & ~ X*/
- if (TREE_CODE (arg1) == BIT_IOR_EXPR
- && operand_equal_p (TREE_OPERAND (arg1, 1), arg0, 0))
- {
- tree t2 = TREE_OPERAND (arg1, 0);
- t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg0),
- arg0);
- t1 = fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_convert_loc (loc, type, t2),
- fold_convert_loc (loc, type, t1));
- return t1;
- }
-
- /* Convert ~X ^ ~Y to X ^ Y. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && TREE_CODE (arg1) == BIT_NOT_EXPR)
- return fold_build2_loc (loc, code, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 0)),
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 0)));
-
- /* Convert ~X ^ C to X ^ ~C. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && TREE_CODE (arg1) == INTEGER_CST)
- return fold_build2_loc (loc, code, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 0)),
- fold_build1_loc (loc, BIT_NOT_EXPR, type, arg1));
-
/* Fold (X & 1) ^ 1 as (X & 1) == 0. */
if (TREE_CODE (arg0) == BIT_AND_EXPR
&& INTEGRAL_TYPE_P (type)
return fold_build2_loc (loc, EQ_EXPR, type, arg0,
build_zero_cst (TREE_TYPE (arg0)));
- /* Fold (X & Y) ^ Y as ~X & Y. */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
- {
- tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
- return fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_build1_loc (loc, BIT_NOT_EXPR, type, tem),
- fold_convert_loc (loc, type, arg1));
- }
- /* Fold (X & Y) ^ X as ~Y & X. */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
- && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
- {
- tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
- return fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_build1_loc (loc, BIT_NOT_EXPR, type, tem),
- fold_convert_loc (loc, type, arg1));
- }
- /* Fold X ^ (X & Y) as X & ~Y. */
- if (TREE_CODE (arg1) == BIT_AND_EXPR
- && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
- {
- tem = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1));
- return fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_convert_loc (loc, type, arg0),
- fold_build1_loc (loc, BIT_NOT_EXPR, type, tem));
- }
- /* Fold X ^ (Y & X) as ~Y & X. */
- if (TREE_CODE (arg1) == BIT_AND_EXPR
- && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
- && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
- {
- tem = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0));
- return fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_build1_loc (loc, BIT_NOT_EXPR, type, tem),
- fold_convert_loc (loc, type, arg0));
- }
-
/* See if this can be simplified into a rotate first. If that
is unsuccessful continue in the association code. */
goto bit_rotate;
case BIT_AND_EXPR:
- /* ~X & X, (X == 0) & X, and !X & X are always zero. */
- if ((TREE_CODE (arg0) == BIT_NOT_EXPR
- || TREE_CODE (arg0) == TRUTH_NOT_EXPR
- || (TREE_CODE (arg0) == EQ_EXPR
- && integer_zerop (TREE_OPERAND (arg0, 1))))
- && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
- return omit_one_operand_loc (loc, type, integer_zero_node, arg1);
-
- /* X & ~X , X & (X == 0), and X & !X are always zero. */
- if ((TREE_CODE (arg1) == BIT_NOT_EXPR
- || TREE_CODE (arg1) == TRUTH_NOT_EXPR
- || (TREE_CODE (arg1) == EQ_EXPR
- && integer_zerop (TREE_OPERAND (arg1, 1))))
- && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
- return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
-
/* Fold (X ^ 1) & 1 as (X & 1) == 0. */
if (TREE_CODE (arg0) == BIT_XOR_EXPR
&& INTEGRAL_TYPE_P (type)
}
}
- t1 = distribute_bit_expr (loc, code, type, arg0, arg1);
- if (t1 != NULL_TREE)
- return t1;
/* Simplify ((int)c & 0377) into (int)c, if c is unsigned char. */
if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
&& TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
}
- /* Convert (and (not arg0) (not arg1)) to (not (or (arg0) (arg1))).
-
- This results in more efficient code for machines without a NOR
- instruction. Combine will canonicalize to the first form
- which will allow use of NOR instructions provided by the
- backend if they exist. */
- if (TREE_CODE (arg0) == BIT_NOT_EXPR
- && TREE_CODE (arg1) == BIT_NOT_EXPR)
- {
- return fold_build1_loc (loc, BIT_NOT_EXPR, type,
- build2 (BIT_IOR_EXPR, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 0)),
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 0))));
- }
-
- /* If arg0 is derived from the address of an object or function, we may
- be able to fold this expression using the object or function's
- alignment. */
- if (POINTER_TYPE_P (TREE_TYPE (arg0)) && tree_fits_uhwi_p (arg1))
- {
- unsigned HOST_WIDE_INT modulus, residue;
- unsigned HOST_WIDE_INT low = tree_to_uhwi (arg1);
-
- modulus = get_pointer_modulus_and_residue (arg0, &residue,
- integer_onep (arg1));
-
- /* This works because modulus is a power of 2. If this weren't the
- case, we'd have to replace it by its greatest power-of-2
- divisor: modulus & -modulus. */
- if (low < modulus)
- return build_int_cst (type, residue & low);
- }
-
- /* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
- (X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1))
- if the new mask might be further optimized. */
- if ((TREE_CODE (arg0) == LSHIFT_EXPR
- || TREE_CODE (arg0) == RSHIFT_EXPR)
- && TYPE_PRECISION (TREE_TYPE (arg0)) <= HOST_BITS_PER_WIDE_INT
- && TREE_CODE (arg1) == INTEGER_CST
- && tree_fits_uhwi_p (TREE_OPERAND (arg0, 1))
- && tree_to_uhwi (TREE_OPERAND (arg0, 1)) > 0
- && (tree_to_uhwi (TREE_OPERAND (arg0, 1))
- < TYPE_PRECISION (TREE_TYPE (arg0))))
- {
- unsigned int shiftc = tree_to_uhwi (TREE_OPERAND (arg0, 1));
- unsigned HOST_WIDE_INT mask = TREE_INT_CST_LOW (arg1);
- unsigned HOST_WIDE_INT newmask, zerobits = 0;
- tree shift_type = TREE_TYPE (arg0);
-
- if (TREE_CODE (arg0) == LSHIFT_EXPR)
- zerobits = ((((unsigned HOST_WIDE_INT) 1) << shiftc) - 1);
- else if (TREE_CODE (arg0) == RSHIFT_EXPR
- && TYPE_PRECISION (TREE_TYPE (arg0))
- == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg0))))
- {
- prec = TYPE_PRECISION (TREE_TYPE (arg0));
- tree arg00 = TREE_OPERAND (arg0, 0);
- /* See if more bits can be proven as zero because of
- zero extension. */
- if (TREE_CODE (arg00) == NOP_EXPR
- && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg00, 0))))
- {
- tree inner_type = TREE_TYPE (TREE_OPERAND (arg00, 0));
- if (TYPE_PRECISION (inner_type)
- == GET_MODE_PRECISION (TYPE_MODE (inner_type))
- && TYPE_PRECISION (inner_type) < prec)
- {
- prec = TYPE_PRECISION (inner_type);
- /* See if we can shorten the right shift. */
- if (shiftc < prec)
- shift_type = inner_type;
- /* Otherwise X >> C1 is all zeros, so we'll optimize
- it into (X, 0) later on by making sure zerobits
- is all ones. */
- }
- }
- zerobits = ~(unsigned HOST_WIDE_INT) 0;
- if (shiftc < prec)
- {
- zerobits >>= HOST_BITS_PER_WIDE_INT - shiftc;
- zerobits <<= prec - shiftc;
- }
- /* For arithmetic shift if sign bit could be set, zerobits
- can contain actually sign bits, so no transformation is
- possible, unless MASK masks them all away. In that
- case the shift needs to be converted into logical shift. */
- if (!TYPE_UNSIGNED (TREE_TYPE (arg0))
- && prec == TYPE_PRECISION (TREE_TYPE (arg0)))
- {
- if ((mask & zerobits) == 0)
- shift_type = unsigned_type_for (TREE_TYPE (arg0));
- else
- zerobits = 0;
- }
- }
-
- /* ((X << 16) & 0xff00) is (X, 0). */
- if ((mask & zerobits) == mask)
- return omit_one_operand_loc (loc, type,
- build_int_cst (type, 0), arg0);
-
- newmask = mask | zerobits;
- if (newmask != mask && (newmask & (newmask + 1)) == 0)
- {
- /* Only do the transformation if NEWMASK is some integer
- mode's mask. */
- for (prec = BITS_PER_UNIT;
- prec < HOST_BITS_PER_WIDE_INT; prec <<= 1)
- if (newmask == (((unsigned HOST_WIDE_INT) 1) << prec) - 1)
- break;
- if (prec < HOST_BITS_PER_WIDE_INT
- || newmask == ~(unsigned HOST_WIDE_INT) 0)
- {
- tree newmaskt;
-
- if (shift_type != TREE_TYPE (arg0))
- {
- tem = fold_build2_loc (loc, TREE_CODE (arg0), shift_type,
- fold_convert_loc (loc, shift_type,
- TREE_OPERAND (arg0, 0)),
- TREE_OPERAND (arg0, 1));
- tem = fold_convert_loc (loc, type, tem);
- }
- else
- tem = op0;
- newmaskt = build_int_cst_type (TREE_TYPE (op1), newmask);
- if (!tree_int_cst_equal (newmaskt, arg1))
- return fold_build2_loc (loc, BIT_AND_EXPR, type, tem, newmaskt);
- }
- }
- }
-
goto associate;
case RDIV_EXPR:
TREE_OPERAND (arg1, 0));
}
- if (flag_unsafe_math_optimizations)
- {
- enum built_in_function fcode0 = builtin_mathfn_code (arg0);
- enum built_in_function fcode1 = builtin_mathfn_code (arg1);
-
- /* Optimize sin(x)/cos(x) as tan(x). */
- if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS)
- || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF)
- || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL))
- && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
- CALL_EXPR_ARG (arg1, 0), 0))
- {
- tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
-
- if (tanfn != NULL_TREE)
- return build_call_expr_loc (loc, tanfn, 1, CALL_EXPR_ARG (arg0, 0));
- }
-
- /* Optimize cos(x)/sin(x) as 1.0/tan(x). */
- if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN)
- || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF)
- || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL))
- && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
- CALL_EXPR_ARG (arg1, 0), 0))
- {
- tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
-
- if (tanfn != NULL_TREE)
- {
- tree tmp = build_call_expr_loc (loc, tanfn, 1,
- CALL_EXPR_ARG (arg0, 0));
- return fold_build2_loc (loc, RDIV_EXPR, type,
- build_real (type, dconst1), tmp);
- }
- }
-
- /* Optimize sin(x)/tan(x) as cos(x) if we don't care about
- NaNs or Infinities. */
- if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_TAN)
- || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_TANF)
- || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_TANL)))
- {
- tree arg00 = CALL_EXPR_ARG (arg0, 0);
- tree arg01 = CALL_EXPR_ARG (arg1, 0);
-
- if (! HONOR_NANS (element_mode (arg00))
- && ! HONOR_INFINITIES (element_mode (arg00))
- && operand_equal_p (arg00, arg01, 0))
- {
- tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
-
- if (cosfn != NULL_TREE)
- return build_call_expr_loc (loc, cosfn, 1, arg00);
- }
- }
-
- /* Optimize tan(x)/sin(x) as 1.0/cos(x) if we don't care about
- NaNs or Infinities. */
- if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_SIN)
- || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_SINF)
- || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_SINL)))
- {
- tree arg00 = CALL_EXPR_ARG (arg0, 0);
- tree arg01 = CALL_EXPR_ARG (arg1, 0);
-
- if (! HONOR_NANS (element_mode (arg00))
- && ! HONOR_INFINITIES (element_mode (arg00))
- && operand_equal_p (arg00, arg01, 0))
- {
- tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
-
- if (cosfn != NULL_TREE)
- {
- tree tmp = build_call_expr_loc (loc, cosfn, 1, arg00);
- return fold_build2_loc (loc, RDIV_EXPR, type,
- build_real (type, dconst1),
- tmp);
- }
- }
- }
-
- /* Optimize pow(x,c)/x as pow(x,c-1). */
- if (fcode0 == BUILT_IN_POW
- || fcode0 == BUILT_IN_POWF
- || fcode0 == BUILT_IN_POWL)
- {
- tree arg00 = CALL_EXPR_ARG (arg0, 0);
- tree arg01 = CALL_EXPR_ARG (arg0, 1);
- if (TREE_CODE (arg01) == REAL_CST
- && !TREE_OVERFLOW (arg01)
- && operand_equal_p (arg1, arg00, 0))
- {
- tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
- REAL_VALUE_TYPE c;
- tree arg;
-
- c = TREE_REAL_CST (arg01);
- real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
- arg = build_real (type, c);
- return build_call_expr_loc (loc, powfn, 2, arg1, arg);
- }
- }
-
- /* Optimize a/root(b/c) into a*root(c/b). */
- if (BUILTIN_ROOT_P (fcode1))
- {
- tree rootarg = CALL_EXPR_ARG (arg1, 0);
-
- if (TREE_CODE (rootarg) == RDIV_EXPR)
- {
- tree rootfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
- tree b = TREE_OPERAND (rootarg, 0);
- tree c = TREE_OPERAND (rootarg, 1);
-
- tree tmp = fold_build2_loc (loc, RDIV_EXPR, type, c, b);
-
- tmp = build_call_expr_loc (loc, rootfn, 1, tmp);
- return fold_build2_loc (loc, MULT_EXPR, type, arg0, tmp);
- }
- }
-
- /* Optimize x/expN(y) into x*expN(-y). */
- if (BUILTIN_EXPONENT_P (fcode1))
- {
- tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
- tree arg = negate_expr (CALL_EXPR_ARG (arg1, 0));
- arg1 = build_call_expr_loc (loc,
- expfn, 1,
- fold_convert_loc (loc, type, arg));
- return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1);
- }
-
- /* Optimize x/pow(y,z) into x*pow(y,-z). */
- if (fcode1 == BUILT_IN_POW
- || fcode1 == BUILT_IN_POWF
- || fcode1 == BUILT_IN_POWL)
- {
- tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
- tree arg10 = CALL_EXPR_ARG (arg1, 0);
- tree arg11 = CALL_EXPR_ARG (arg1, 1);
- tree neg11 = fold_convert_loc (loc, type,
- negate_expr (arg11));
- arg1 = build_call_expr_loc (loc, powfn, 2, arg10, neg11);
- return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1);
- }
- }
return NULL_TREE;
case TRUNC_DIV_EXPR:
after the last round to changes to the DIV code in expmed.c. */
if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR)
&& multiple_of_p (type, arg0, arg1))
- return fold_build2_loc (loc, EXACT_DIV_EXPR, type, arg0, arg1);
+ return fold_build2_loc (loc, EXACT_DIV_EXPR, type,
+ fold_convert (type, arg0),
+ fold_convert (type, arg1));
strict_overflow_p = false;
if (TREE_CODE (arg1) == INTEGER_CST
case FLOOR_MOD_EXPR:
case ROUND_MOD_EXPR:
case TRUNC_MOD_EXPR:
- /* X % -Y is the same as X % Y. */
- if (code == TRUNC_MOD_EXPR
- && !TYPE_UNSIGNED (type)
- && TREE_CODE (arg1) == NEGATE_EXPR
- && !TYPE_OVERFLOW_TRAPS (type))
- return fold_build2_loc (loc, code, type, fold_convert_loc (loc, type, arg0),
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg1, 0)));
-
strict_overflow_p = false;
if (TREE_CODE (arg1) == INTEGER_CST
&& 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE,
return fold_convert_loc (loc, type, tem);
}
- /* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR,
- i.e. "X % C" into "X & (C - 1)", if X and C are positive. */
- if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR)
- && (TYPE_UNSIGNED (type)
- || tree_expr_nonnegative_warnv_p (op0, &strict_overflow_p)))
- {
- tree c = arg1;
- /* Also optimize A % (C << N) where C is a power of 2,
- to A & ((C << N) - 1). */
- if (TREE_CODE (arg1) == LSHIFT_EXPR)
- c = TREE_OPERAND (arg1, 0);
-
- if (integer_pow2p (c) && tree_int_cst_sgn (c) > 0)
- {
- tree mask
- = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (arg1), arg1,
- build_int_cst (TREE_TYPE (arg1), 1));
- if (strict_overflow_p)
- fold_overflow_warning (("assuming signed overflow does not "
- "occur when simplifying "
- "X % (power of two)"),
- WARN_STRICT_OVERFLOW_MISC);
- return fold_build2_loc (loc, BIT_AND_EXPR, type,
- fold_convert_loc (loc, type, arg0),
- fold_convert_loc (loc, type, mask));
- }
- }
-
return NULL_TREE;
case LROTATE_EXPR:
prec = element_precision (type);
- /* Turn (a OP c1) OP c2 into a OP (c1+c2). */
- if (TREE_CODE (op0) == code && tree_fits_uhwi_p (arg1)
- && tree_to_uhwi (arg1) < prec
- && tree_fits_uhwi_p (TREE_OPERAND (arg0, 1))
- && tree_to_uhwi (TREE_OPERAND (arg0, 1)) < prec)
- {
- unsigned int low = (tree_to_uhwi (TREE_OPERAND (arg0, 1))
- + tree_to_uhwi (arg1));
-
- /* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
- being well defined. */
- if (low >= prec)
- {
- if (code == LROTATE_EXPR || code == RROTATE_EXPR)
- low = low % prec;
- else if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
- return omit_one_operand_loc (loc, type, build_zero_cst (type),
- TREE_OPERAND (arg0, 0));
- else
- low = prec - 1;
- }
-
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
- build_int_cst (TREE_TYPE (arg1), low));
- }
-
- /* Transform (x >> c) << c into x & (-1<<c), or transform (x << c) >> c
- into x & ((unsigned)-1 >> c) for unsigned types. */
- if (((code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR)
- || (TYPE_UNSIGNED (type)
- && code == RSHIFT_EXPR && TREE_CODE (arg0) == LSHIFT_EXPR))
- && tree_fits_uhwi_p (arg1)
- && tree_to_uhwi (arg1) < prec
- && tree_fits_uhwi_p (TREE_OPERAND (arg0, 1))
- && tree_to_uhwi (TREE_OPERAND (arg0, 1)) < prec)
- {
- HOST_WIDE_INT low0 = tree_to_uhwi (TREE_OPERAND (arg0, 1));
- HOST_WIDE_INT low1 = tree_to_uhwi (arg1);
- tree lshift;
- tree arg00;
-
- if (low0 == low1)
- {
- arg00 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
-
- lshift = build_minus_one_cst (type);
- lshift = const_binop (code, lshift, arg1);
-
- return fold_build2_loc (loc, BIT_AND_EXPR, type, arg00, lshift);
- }
- }
-
/* If we have a rotate of a bit operation with the rotate count and
the second operand of the bit operation both constant,
permute the two operations. */
prec) == 0)
return TREE_OPERAND (arg0, 0);
- /* Fold (X & C2) << C1 into (X << C1) & (C2 << C1)
- (X & C2) >> C1 into (X >> C1) & (C2 >> C1)
- if the latter can be further optimized. */
- if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR)
- && TREE_CODE (arg0) == BIT_AND_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- {
- tree mask = fold_build2_loc (loc, code, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 1)),
- arg1);
- tree shift = fold_build2_loc (loc, code, type,
- fold_convert_loc (loc, type,
- TREE_OPERAND (arg0, 0)),
- arg1);
- tem = fold_binary_loc (loc, BIT_AND_EXPR, type, shift, mask);
- if (tem)
- return tem;
- }
-
return NULL_TREE;
case MIN_EXPR:
if (tem != NULL_TREE)
return tem;
- /* bool_var != 0 becomes bool_var. */
- if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
- && code == NE_EXPR)
- return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0));
-
- /* bool_var == 1 becomes bool_var. */
- if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
- && code == EQ_EXPR)
- return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0));
-
/* bool_var != 1 becomes !bool_var. */
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
&& code == NE_EXPR)
&& code == NE_EXPR)
return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0));
- /* If this is an equality comparison of the address of two non-weak,
- unaliased symbols neither of which are extern (since we do not
- have access to attributes for externs), then we know the result. */
- if (TREE_CODE (arg0) == ADDR_EXPR
- && DECL_P (TREE_OPERAND (arg0, 0))
- && TREE_CODE (arg1) == ADDR_EXPR
- && DECL_P (TREE_OPERAND (arg1, 0)))
- {
- int equal;
-
- if (decl_in_symtab_p (TREE_OPERAND (arg0, 0))
- && decl_in_symtab_p (TREE_OPERAND (arg1, 0)))
- equal = symtab_node::get_create (TREE_OPERAND (arg0, 0))
- ->equal_address_to (symtab_node::get_create
- (TREE_OPERAND (arg1, 0)));
- else
- equal = TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0);
- if (equal != 2)
- return constant_boolean_node (equal
- ? code == EQ_EXPR : code != EQ_EXPR,
- type);
- }
-
- /* Similarly for a NEGATE_EXPR. */
- if (TREE_CODE (arg0) == NEGATE_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && 0 != (tem = negate_expr (fold_convert_loc (loc, TREE_TYPE (arg0),
- arg1)))
- && TREE_CODE (tem) == INTEGER_CST
- && !TREE_OVERFLOW (tem))
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem);
-
- /* Similarly for a BIT_XOR_EXPR; X ^ C1 == C2 is X == (C1 ^ C2). */
- if (TREE_CODE (arg0) == BIT_XOR_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
- fold_build2_loc (loc, BIT_XOR_EXPR, TREE_TYPE (arg0),
- fold_convert_loc (loc,
- TREE_TYPE (arg0),
- arg1),
- TREE_OPERAND (arg0, 1)));
-
/* Transform comparisons of the form X +- Y CMP X to Y CMP 0. */
if ((TREE_CODE (arg0) == PLUS_EXPR
|| TREE_CODE (arg0) == POINTER_PLUS_EXPR
TREE_OPERAND (arg0, 1), arg1);
}
- /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0. */
- if (TREE_CODE (arg0) == ABS_EXPR
- && (integer_zerop (arg1) || real_zerop (arg1)))
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), arg1);
-
/* If this is an EQ or NE comparison with zero and ARG0 is
(1 << foo) & bar, convert it to (bar >> foo) & 1. Both require
two operations, but the latter can be done in one less insn
}
}
- /* If we have (A & C) == C where C is a power of 2, convert this into
- (A & C) != 0. Similarly for NE_EXPR. */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && integer_pow2p (TREE_OPERAND (arg0, 1))
- && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
- return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
- arg0, fold_convert_loc (loc, TREE_TYPE (arg0),
- integer_zero_node));
-
- /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign
- bit, then fold the expression into A < 0 or A >= 0. */
- tem = fold_single_bit_test_into_sign_test (loc, code, arg0, arg1, type);
- if (tem)
- return tem;
-
/* If we have (A & C) == D where D & ~C != 0, convert this into 0.
Similarly for NE_EXPR. */
if (TREE_CODE (arg0) == BIT_AND_EXPR
return omit_one_operand_loc (loc, type, rslt, arg0);
}
- /* If we have (A | C) == D where C & ~D != 0, convert this into 0.
- Similarly for NE_EXPR. */
- if (TREE_CODE (arg0) == BIT_IOR_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- {
- tree notd = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg1), arg1);
- tree candnotd
- = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
- TREE_OPERAND (arg0, 1),
- fold_convert_loc (loc, TREE_TYPE (arg0), notd));
- tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
- if (integer_nonzerop (candnotd))
- return omit_one_operand_loc (loc, type, rslt, arg0);
- }
-
/* If this is a comparison of a field, we may be able to simplify it. */
if ((TREE_CODE (arg0) == COMPONENT_REF
|| TREE_CODE (arg0) == BIT_FIELD_REF)
}
}
- /* (X ^ Y) == 0 becomes X == Y, and (X ^ Y) != 0 becomes X != Y. */
- if (integer_zerop (arg1)
- && TREE_CODE (arg0) == BIT_XOR_EXPR)
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg0, 1));
-
- /* (X ^ Y) == Y becomes X == 0. We know that Y has no side-effects. */
- if (TREE_CODE (arg0) == BIT_XOR_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
- build_zero_cst (TREE_TYPE (arg0)));
- /* Likewise (X ^ Y) == X becomes Y == 0. X has no side-effects. */
- if (TREE_CODE (arg0) == BIT_XOR_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
- && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 1),
- build_zero_cst (TREE_TYPE (arg0)));
-
- /* (X ^ C1) op C2 can be rewritten as X op (C1 ^ C2). */
- if (TREE_CODE (arg0) == BIT_XOR_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
- fold_build2_loc (loc, BIT_XOR_EXPR, TREE_TYPE (arg1),
- TREE_OPERAND (arg0, 1), arg1));
-
/* Fold (~X & C) == 0 into (X & C) != 0 and (~X & C) != 0 into
(X & C) == 0 when C is a single bit. */
if (TREE_CODE (arg0) == BIT_AND_EXPR
return omit_one_operand_loc (loc, type, res, arg0);
}
- /* Fold -X op -Y as X op Y, where op is eq/ne. */
- if (TREE_CODE (arg0) == NEGATE_EXPR
- && TREE_CODE (arg1) == NEGATE_EXPR)
- return fold_build2_loc (loc, code, type,
- TREE_OPERAND (arg0, 0),
- fold_convert_loc (loc, TREE_TYPE (arg0),
- TREE_OPERAND (arg1, 0)));
-
/* Fold (X & C) op (Y & C) as (X ^ Y) & C op 0", and symmetries. */
if (TREE_CODE (arg0) == BIT_AND_EXPR
&& TREE_CODE (arg1) == BIT_AND_EXPR)
if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
&& operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
&& ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
- && !HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
+ && !HONOR_SNANS (arg0))
|| (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))))
{
}
/* Convert (X - c) <= X to true. */
- if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
+ if (!HONOR_NANS (arg1)
&& code == LE_EXPR
&& ((code0 == MINUS_EXPR && is_positive >= 0)
|| (code0 == PLUS_EXPR && is_positive <= 0)))
}
/* Convert (X + c) >= X to true. */
- if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
+ if (!HONOR_NANS (arg1)
&& code == GE_EXPR
&& ((code0 == PLUS_EXPR && is_positive >= 0)
|| (code0 == MINUS_EXPR && is_positive <= 0)))
"not occur when assuming that "
"(X - c) < X is always true"),
WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (1, type);
- }
-
- /* Convert X + c <= X and X - c >= X to false for integers. */
- if (code == LE_EXPR
- && ((code0 == PLUS_EXPR && is_positive > 0)
- || (code0 == MINUS_EXPR && is_positive < 0)))
- {
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does "
- "not occur when assuming that "
- "(X + c) <= X is always false"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (0, type);
- }
-
- if (code == GE_EXPR
- && ((code0 == MINUS_EXPR && is_positive > 0)
- || (code0 == PLUS_EXPR && is_positive < 0)))
- {
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does "
- "not occur when assuming that "
- "(X - c) >= X is always false"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (0, type);
- }
- }
- }
-
- /* Comparisons with the highest or lowest possible integer of
- the specified precision will have known values. */
- {
- tree arg1_type = TREE_TYPE (arg1);
- unsigned int prec = TYPE_PRECISION (arg1_type);
-
- if (TREE_CODE (arg1) == INTEGER_CST
- && (INTEGRAL_TYPE_P (arg1_type) || POINTER_TYPE_P (arg1_type)))
- {
- wide_int max = wi::max_value (arg1_type);
- wide_int signed_max = wi::max_value (prec, SIGNED);
- wide_int min = wi::min_value (arg1_type);
-
- if (wi::eq_p (arg1, max))
- switch (code)
- {
- case GT_EXPR:
- return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
-
- case GE_EXPR:
- return fold_build2_loc (loc, EQ_EXPR, type, op0, op1);
-
- case LE_EXPR:
- return omit_one_operand_loc (loc, type, integer_one_node, arg0);
-
- case LT_EXPR:
- return fold_build2_loc (loc, NE_EXPR, type, op0, op1);
-
- /* The GE_EXPR and LT_EXPR cases above are not normally
- reached because of previous transformations. */
-
- default:
- break;
- }
- else if (wi::eq_p (arg1, max - 1))
- switch (code)
- {
- case GT_EXPR:
- arg1 = const_binop (PLUS_EXPR, arg1,
- build_int_cst (TREE_TYPE (arg1), 1));
- return fold_build2_loc (loc, EQ_EXPR, type,
- fold_convert_loc (loc,
- TREE_TYPE (arg1), arg0),
- arg1);
- case LE_EXPR:
- arg1 = const_binop (PLUS_EXPR, arg1,
- build_int_cst (TREE_TYPE (arg1), 1));
- return fold_build2_loc (loc, NE_EXPR, type,
- fold_convert_loc (loc, TREE_TYPE (arg1),
- arg0),
- arg1);
- default:
- break;
- }
- else if (wi::eq_p (arg1, min))
- switch (code)
- {
- case LT_EXPR:
- return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
-
- case LE_EXPR:
- return fold_build2_loc (loc, EQ_EXPR, type, op0, op1);
-
- case GE_EXPR:
- return omit_one_operand_loc (loc, type, integer_one_node, arg0);
-
- case GT_EXPR:
- return fold_build2_loc (loc, NE_EXPR, type, op0, op1);
-
- default:
- break;
+ return constant_boolean_node (1, type);
}
- else if (wi::eq_p (arg1, min + 1))
- switch (code)
+
+ /* Convert X + c <= X and X - c >= X to false for integers. */
+ if (code == LE_EXPR
+ && ((code0 == PLUS_EXPR && is_positive > 0)
+ || (code0 == MINUS_EXPR && is_positive < 0)))
{
- case GE_EXPR:
- arg1 = const_binop (MINUS_EXPR, arg1,
- build_int_cst (TREE_TYPE (arg1), 1));
- return fold_build2_loc (loc, NE_EXPR, type,
- fold_convert_loc (loc,
- TREE_TYPE (arg1), arg0),
- arg1);
- case LT_EXPR:
- arg1 = const_binop (MINUS_EXPR, arg1,
- build_int_cst (TREE_TYPE (arg1), 1));
- return fold_build2_loc (loc, EQ_EXPR, type,
- fold_convert_loc (loc, TREE_TYPE (arg1),
- arg0),
- arg1);
- default:
- break;
+ if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does "
+ "not occur when assuming that "
+ "(X + c) <= X is always false"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (0, type);
}
- else if (wi::eq_p (arg1, signed_max)
- && TYPE_UNSIGNED (arg1_type)
- /* We will flip the signedness of the comparison operator
- associated with the mode of arg1, so the sign bit is
- specified by this mode. Check that arg1 is the signed
- max associated with this sign bit. */
- && prec == GET_MODE_PRECISION (TYPE_MODE (arg1_type))
- /* signed_type does not work on pointer types. */
- && INTEGRAL_TYPE_P (arg1_type))
- {
- /* The following case also applies to X < signed_max+1
- and X >= signed_max+1 because previous transformations. */
- if (code == LE_EXPR || code == GT_EXPR)
- {
- tree st = signed_type_for (arg1_type);
- return fold_build2_loc (loc,
- code == LE_EXPR ? GE_EXPR : LT_EXPR,
- type, fold_convert_loc (loc, st, arg0),
- build_int_cst (st, 0));
- }
- }
- }
- }
+ if (code == GE_EXPR
+ && ((code0 == MINUS_EXPR && is_positive > 0)
+ || (code0 == PLUS_EXPR && is_positive < 0)))
+ {
+ if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does "
+ "not occur when assuming that "
+ "(X - c) >= X is always false"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (0, type);
+ }
+ }
+ }
/* If we are comparing an ABS_EXPR with a constant, we can
convert all the cases into explicit comparisons, but they may
strict_overflow_p = false;
if (code == GE_EXPR
&& (integer_zerop (arg1)
- || (! HONOR_NANS (element_mode (arg0))
+ || (! HONOR_NANS (arg0)
&& real_zerop (arg1)))
&& tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
{
case UNGE_EXPR:
case UNEQ_EXPR:
case LTGT_EXPR:
- if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
- {
- t1 = fold_relational_const (code, type, arg0, arg1);
- if (t1 != NULL_TREE)
- return t1;
- }
-
- /* If the first operand is NaN, the result is constant. */
- if (TREE_CODE (arg0) == REAL_CST
- && REAL_VALUE_ISNAN (TREE_REAL_CST (arg0))
- && (code != LTGT_EXPR || ! flag_trapping_math))
- {
- t1 = (code == ORDERED_EXPR || code == LTGT_EXPR)
- ? integer_zero_node
- : integer_one_node;
- return omit_one_operand_loc (loc, type, t1, arg1);
- }
-
- /* If the second operand is NaN, the result is constant. */
- if (TREE_CODE (arg1) == REAL_CST
- && REAL_VALUE_ISNAN (TREE_REAL_CST (arg1))
- && (code != LTGT_EXPR || ! flag_trapping_math))
- {
- t1 = (code == ORDERED_EXPR || code == LTGT_EXPR)
- ? integer_zero_node
- : integer_one_node;
- return omit_one_operand_loc (loc, type, t1, arg0);
- }
-
- /* Simplify unordered comparison of something with itself. */
- if ((code == UNLE_EXPR || code == UNGE_EXPR || code == UNEQ_EXPR)
- && operand_equal_p (arg0, arg1, 0))
- return constant_boolean_node (1, type);
-
- if (code == LTGT_EXPR
- && !flag_trapping_math
- && operand_equal_p (arg0, arg1, 0))
- return constant_boolean_node (0, type);
-
/* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */
{
tree targ0 = strip_float_extensions (arg0);
#undef fold
static void fold_checksum_tree (const_tree, struct md5_ctx *,
- hash_table<pointer_hash<const tree_node> > *);
+ hash_table<nofree_ptr_hash<const tree_node> > *);
static void fold_check_failed (const_tree, const_tree);
void print_fold_checksum (const_tree);
tree ret;
struct md5_ctx ctx;
unsigned char checksum_before[16], checksum_after[16];
- hash_table<pointer_hash<const tree_node> > ht (32);
+ hash_table<nofree_ptr_hash<const tree_node> > ht (32);
md5_init_ctx (&ctx);
fold_checksum_tree (expr, &ctx, &ht);
{
struct md5_ctx ctx;
unsigned char checksum[16], cnt;
- hash_table<pointer_hash<const tree_node> > ht (32);
+ hash_table<nofree_ptr_hash<const tree_node> > ht (32);
md5_init_ctx (&ctx);
fold_checksum_tree (expr, &ctx, &ht);
static void
fold_checksum_tree (const_tree expr, struct md5_ctx *ctx,
- hash_table<pointer_hash <const tree_node> > *ht)
+ hash_table<nofree_ptr_hash <const tree_node> > *ht)
{
const tree_node **slot;
enum tree_code code;
*slot = expr;
code = TREE_CODE (expr);
if (TREE_CODE_CLASS (code) == tcc_declaration
- && DECL_ASSEMBLER_NAME_SET_P (expr))
+ && HAS_DECL_ASSEMBLER_NAME_P (expr))
{
- /* Allow DECL_ASSEMBLER_NAME to be modified. */
+ /* Allow DECL_ASSEMBLER_NAME and symtab_node to be modified. */
memcpy ((char *) &buf, expr, tree_size (expr));
SET_DECL_ASSEMBLER_NAME ((tree)&buf, NULL);
+ buf.decl_with_vis.symtab_node = NULL;
expr = (tree) &buf;
}
else if (TREE_CODE_CLASS (code) == tcc_type
int i;
unsigned char checksum[16];
struct md5_ctx ctx;
- hash_table<pointer_hash<const tree_node> > ht (32);
+ hash_table<nofree_ptr_hash<const tree_node> > ht (32);
md5_init_ctx (&ctx);
fold_checksum_tree (t, &ctx, &ht);
#ifdef ENABLE_FOLD_CHECKING
unsigned char checksum_before[16], checksum_after[16];
struct md5_ctx ctx;
- hash_table<pointer_hash<const tree_node> > ht (32);
+ hash_table<nofree_ptr_hash<const tree_node> > ht (32);
md5_init_ctx (&ctx);
fold_checksum_tree (op0, &ctx, &ht);
checksum_after_op0[16],
checksum_after_op1[16];
struct md5_ctx ctx;
- hash_table<pointer_hash<const tree_node> > ht (32);
+ hash_table<nofree_ptr_hash<const tree_node> > ht (32);
md5_init_ctx (&ctx);
fold_checksum_tree (op0, &ctx, &ht);
checksum_after_op1[16],
checksum_after_op2[16];
struct md5_ctx ctx;
- hash_table<pointer_hash<const tree_node> > ht (32);
+ hash_table<nofree_ptr_hash<const tree_node> > ht (32);
md5_init_ctx (&ctx);
fold_checksum_tree (op0, &ctx, &ht);
checksum_after_fn[16],
checksum_after_arglist[16];
struct md5_ctx ctx;
- hash_table<pointer_hash<const tree_node> > ht (32);
+ hash_table<nofree_ptr_hash<const tree_node> > ht (32);
int i;
md5_init_ctx (&ctx);
}
}
+#define tree_expr_nonnegative_warnv_p(X, Y) \
+ _Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0
+
+#define RECURSE(X) \
+ ((tree_expr_nonnegative_warnv_p) (X, strict_overflow_p, depth + 1))
+
/* Return true if CODE or TYPE is known to be non-negative. */
static bool
/* Return true if (CODE OP0) is known to be non-negative. If the return
value is based on the assumption that signed overflow is undefined,
set *STRICT_OVERFLOW_P to true; otherwise, don't change
- *STRICT_OVERFLOW_P. */
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
bool
tree_unary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
- bool *strict_overflow_p)
+ bool *strict_overflow_p, int depth)
{
if (TYPE_UNSIGNED (type))
return true;
case ABS_EXPR:
/* We can't return 1 if flag_wrapv is set because
ABS_EXPR<INT_MIN> = INT_MIN. */
- if (!INTEGRAL_TYPE_P (type))
+ if (!ANY_INTEGRAL_TYPE_P (type))
return true;
if (TYPE_OVERFLOW_UNDEFINED (type))
{
case NON_LVALUE_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
- return tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p);
+ return RECURSE (op0);
CASE_CONVERT:
{
if (TREE_CODE (outer_type) == REAL_TYPE)
{
if (TREE_CODE (inner_type) == REAL_TYPE)
- return tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p);
+ return RECURSE (op0);
if (INTEGRAL_TYPE_P (inner_type))
{
if (TYPE_UNSIGNED (inner_type))
return true;
- return tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p);
+ return RECURSE (op0);
}
}
else if (INTEGRAL_TYPE_P (outer_type))
{
if (TREE_CODE (inner_type) == REAL_TYPE)
- return tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p);
+ return RECURSE (op0);
if (INTEGRAL_TYPE_P (inner_type))
return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)
&& TYPE_UNSIGNED (inner_type);
/* Return true if (CODE OP0 OP1) is known to be non-negative. If the return
value is based on the assumption that signed overflow is undefined,
set *STRICT_OVERFLOW_P to true; otherwise, don't change
- *STRICT_OVERFLOW_P. */
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
bool
tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
- tree op1, bool *strict_overflow_p)
+ tree op1, bool *strict_overflow_p,
+ int depth)
{
if (TYPE_UNSIGNED (type))
return true;
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
if (FLOAT_TYPE_P (type))
- return (tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p)
- && tree_expr_nonnegative_warnv_p (op1,
- strict_overflow_p));
+ return RECURSE (op0) && RECURSE (op1);
/* zero_extend(x) + zero_extend(y) is non-negative if x and y are
both unsigned and at least 2 bits shorter than the result. */
/* x * x is always non-negative for floating point x
or without overflow. */
if (operand_equal_p (op0, op1, 0)
- || (tree_expr_nonnegative_warnv_p (op0, strict_overflow_p)
- && tree_expr_nonnegative_warnv_p (op1, strict_overflow_p)))
+ || (RECURSE (op0) && RECURSE (op1)))
{
- if (TYPE_OVERFLOW_UNDEFINED (type))
+ if (ANY_INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_UNDEFINED (type))
*strict_overflow_p = true;
return true;
}
case BIT_AND_EXPR:
case MAX_EXPR:
- return (tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p)
- || tree_expr_nonnegative_warnv_p (op1,
- strict_overflow_p));
+ return RECURSE (op0) || RECURSE (op1);
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
- return (tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p)
- && tree_expr_nonnegative_warnv_p (op1,
- strict_overflow_p));
+ return RECURSE (op0) && RECURSE (op1);
case TRUNC_MOD_EXPR:
- case CEIL_MOD_EXPR:
+ return RECURSE (op0);
+
case FLOOR_MOD_EXPR:
+ return RECURSE (op1);
+
+ case CEIL_MOD_EXPR:
case ROUND_MOD_EXPR:
- return tree_expr_nonnegative_warnv_p (op0,
- strict_overflow_p);
default:
return tree_simple_nonnegative_warnv_p (code, type);
}
/* Return true if T is known to be non-negative. If the return
value is based on the assumption that signed overflow is undefined,
set *STRICT_OVERFLOW_P to true; otherwise, don't change
- *STRICT_OVERFLOW_P. */
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
bool
-tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
+tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
{
if (TYPE_UNSIGNED (TREE_TYPE (t)))
return true;
return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t));
case COND_EXPR:
- return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
- strict_overflow_p)
- && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2),
- strict_overflow_p));
+ return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2));
+
+ case SSA_NAME:
+ /* Limit the depth of recursion to avoid quadratic behavior.
+ This is expected to catch almost all occurrences in practice.
+ If this code misses important cases that unbounded recursion
+ would not, passes that need this information could be revised
+ to provide it through dataflow propagation. */
+ return (!name_registered_for_update_p (t)
+ && depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH)
+ && gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t),
+ strict_overflow_p, depth));
+
default:
- return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
- TREE_TYPE (t));
+ return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
}
- /* We don't know sign of `t', so be conservative and return false. */
- return false;
}
/* Return true if T is known to be non-negative. If the return
value is based on the assumption that signed overflow is undefined,
set *STRICT_OVERFLOW_P to true; otherwise, don't change
- *STRICT_OVERFLOW_P. */
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
bool
-tree_call_nonnegative_warnv_p (tree type, tree fndecl,
- tree arg0, tree arg1, bool *strict_overflow_p)
+tree_call_nonnegative_warnv_p (tree type, tree fndecl, tree arg0, tree arg1,
+ bool *strict_overflow_p, int depth)
{
if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fndecl))
/* sqrt(-0.0) is -0.0. */
if (!HONOR_SIGNED_ZEROS (element_mode (type)))
return true;
- return tree_expr_nonnegative_warnv_p (arg0,
- strict_overflow_p);
+ return RECURSE (arg0);
CASE_FLT_FN (BUILT_IN_ASINH):
CASE_FLT_FN (BUILT_IN_ATAN):
CASE_FLT_FN (BUILT_IN_TANH):
CASE_FLT_FN (BUILT_IN_TRUNC):
/* True if the 1st argument is nonnegative. */
- return tree_expr_nonnegative_warnv_p (arg0,
- strict_overflow_p);
+ return RECURSE (arg0);
CASE_FLT_FN (BUILT_IN_FMAX):
/* True if the 1st OR 2nd arguments are nonnegative. */
- return (tree_expr_nonnegative_warnv_p (arg0,
- strict_overflow_p)
- || (tree_expr_nonnegative_warnv_p (arg1,
- strict_overflow_p)));
+ return RECURSE (arg0) || RECURSE (arg1);
CASE_FLT_FN (BUILT_IN_FMIN):
/* True if the 1st AND 2nd arguments are nonnegative. */
- return (tree_expr_nonnegative_warnv_p (arg0,
- strict_overflow_p)
- && (tree_expr_nonnegative_warnv_p (arg1,
- strict_overflow_p)));
+ return RECURSE (arg0) && RECURSE (arg1);
CASE_FLT_FN (BUILT_IN_COPYSIGN):
/* True if the 2nd argument is nonnegative. */
- return tree_expr_nonnegative_warnv_p (arg1,
- strict_overflow_p);
+ return RECURSE (arg1);
CASE_FLT_FN (BUILT_IN_POWI):
/* True if the 1st argument is nonnegative or the second
if (TREE_CODE (arg1) == INTEGER_CST
&& (TREE_INT_CST_LOW (arg1) & 1) == 0)
return true;
- return tree_expr_nonnegative_warnv_p (arg0,
- strict_overflow_p);
+ return RECURSE (arg0);
CASE_FLT_FN (BUILT_IN_POW):
/* True if the 1st argument is nonnegative or the second
return true;
}
}
- return tree_expr_nonnegative_warnv_p (arg0,
- strict_overflow_p);
+ return RECURSE (arg0);
default:
break;
}
- return tree_simple_nonnegative_warnv_p (CALL_EXPR,
- type);
+ return tree_simple_nonnegative_warnv_p (CALL_EXPR, type);
}
/* Return true if T is known to be non-negative. If the return
value is based on the assumption that signed overflow is undefined,
set *STRICT_OVERFLOW_P to true; otherwise, don't change
- *STRICT_OVERFLOW_P. */
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
static bool
-tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
+tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
{
enum tree_code code = TREE_CODE (t);
if (TYPE_UNSIGNED (TREE_TYPE (t)))
/* If the initializer is non-void, then it's a normal expression
that will be assigned to the slot. */
if (!VOID_TYPE_P (t))
- return tree_expr_nonnegative_warnv_p (t, strict_overflow_p);
+ return RECURSE (t);
/* Otherwise, the initializer sets the slot in some way. One common
way is an assignment statement at the end of the initializer. */
}
if (TREE_CODE (t) == MODIFY_EXPR
&& TREE_OPERAND (t, 0) == temp)
- return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
- strict_overflow_p);
+ return RECURSE (TREE_OPERAND (t, 1));
return false;
}
get_callee_fndecl (t),
arg0,
arg1,
- strict_overflow_p);
+ strict_overflow_p, depth);
}
case COMPOUND_EXPR:
case MODIFY_EXPR:
- return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
- strict_overflow_p);
+ return RECURSE (TREE_OPERAND (t, 1));
+
case BIND_EXPR:
- return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)),
- strict_overflow_p);
+ return RECURSE (expr_last (TREE_OPERAND (t, 1)));
+
case SAVE_EXPR:
- return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
- strict_overflow_p);
+ return RECURSE (TREE_OPERAND (t, 0));
default:
- return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
- TREE_TYPE (t));
+ return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
}
-
- /* We don't know sign of `t', so be conservative and return false. */
- return false;
}
+#undef RECURSE
+#undef tree_expr_nonnegative_warnv_p
+
/* Return true if T is known to be non-negative. If the return
value is based on the assumption that signed overflow is undefined,
set *STRICT_OVERFLOW_P to true; otherwise, don't change
- *STRICT_OVERFLOW_P. */
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
bool
-tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
+tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
{
enum tree_code code;
if (t == error_mark_node)
TREE_TYPE (t),
TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1),
- strict_overflow_p);
+ strict_overflow_p, depth);
case tcc_unary:
return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
TREE_TYPE (t),
TREE_OPERAND (t, 0),
- strict_overflow_p);
+ strict_overflow_p, depth);
case tcc_constant:
case tcc_declaration:
case tcc_reference:
- return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
+ return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth);
default:
break;
TREE_TYPE (t),
TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1),
- strict_overflow_p);
+ strict_overflow_p, depth);
case TRUTH_NOT_EXPR:
return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
TREE_TYPE (t),
TREE_OPERAND (t, 0),
- strict_overflow_p);
+ strict_overflow_p, depth);
case COND_EXPR:
case CONSTRUCTOR:
case ADDR_EXPR:
case WITH_SIZE_EXPR:
case SSA_NAME:
- return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
+ return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth);
default:
- return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p);
+ return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p, depth);
}
}
{
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
- if (TYPE_OVERFLOW_UNDEFINED (type))
+ if (ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_UNDEFINED (type))
{
/* With the presence of negative values it is hard
to say something. */
return false;
}
+#define integer_valued_real_p(X) \
+ _Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0
+
+#define RECURSE(X) \
+ ((integer_valued_real_p) (X, depth + 1))
+
+/* Return true if the floating point result of (CODE OP0) has an
+ integer value. We also allow +Inf, -Inf and NaN to be considered
+ integer values.
+
+ DEPTH is the current nesting depth of the query. */
+
+bool
+integer_valued_real_unary_p (tree_code code, tree op0, int depth)
+{
+ switch (code)
+ {
+ case FLOAT_EXPR:
+ return true;
+
+ case ABS_EXPR:
+ return RECURSE (op0);
+
+ CASE_CONVERT:
+ {
+ tree type = TREE_TYPE (op0);
+ if (TREE_CODE (type) == INTEGER_TYPE)
+ return true;
+ if (TREE_CODE (type) == REAL_TYPE)
+ return RECURSE (op0);
+ break;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Return true if the floating point result of (CODE OP0 OP1) has an
+ integer value. We also allow +Inf, -Inf and NaN to be considered
+ integer values.
+
+ DEPTH is the current nesting depth of the query. */
+
+bool
+integer_valued_real_binary_p (tree_code code, tree op0, tree op1, int depth)
+{
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
+ return RECURSE (op0) && RECURSE (op1);
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Return true if the floating point result of calling FNDECL with arguments
+ ARG0 and ARG1 has an integer value. We also allow +Inf, -Inf and NaN to be
+ considered integer values. If FNDECL takes fewer than 2 arguments,
+ the remaining ARGn are null.
+
+ DEPTH is the current nesting depth of the query. */
+
+bool
+integer_valued_real_call_p (tree fndecl, tree arg0, tree arg1, int depth)
+{
+ if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ CASE_FLT_FN (BUILT_IN_CEIL):
+ CASE_FLT_FN (BUILT_IN_FLOOR):
+ CASE_FLT_FN (BUILT_IN_NEARBYINT):
+ CASE_FLT_FN (BUILT_IN_RINT):
+ CASE_FLT_FN (BUILT_IN_ROUND):
+ CASE_FLT_FN (BUILT_IN_TRUNC):
+ return true;
+
+ CASE_FLT_FN (BUILT_IN_FMIN):
+ CASE_FLT_FN (BUILT_IN_FMAX):
+ return RECURSE (arg0) && RECURSE (arg1);
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Return true if the floating point expression T (a GIMPLE_SINGLE_RHS)
+ has an integer value. We also allow +Inf, -Inf and NaN to be
+ considered integer values.
+
+ DEPTH is the current nesting depth of the query. */
+
+bool
+integer_valued_real_single_p (tree t, int depth)
+{
+ switch (TREE_CODE (t))
+ {
+ case REAL_CST:
+ return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t)));
+
+ case COND_EXPR:
+ return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2));
+
+ case SSA_NAME:
+ /* Limit the depth of recursion to avoid quadratic behavior.
+ This is expected to catch almost all occurrences in practice.
+ If this code misses important cases that unbounded recursion
+ would not, passes that need this information could be revised
+ to provide it through dataflow propagation. */
+ return (!name_registered_for_update_p (t)
+ && depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH)
+ && gimple_stmt_integer_valued_real_p (SSA_NAME_DEF_STMT (t),
+ depth));
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Return true if the floating point expression T (a GIMPLE_INVALID_RHS)
+ has an integer value. We also allow +Inf, -Inf and NaN to be
+ considered integer values.
+
+ DEPTH is the current nesting depth of the query. */
+
+static bool
+integer_valued_real_invalid_p (tree t, int depth)
+{
+ switch (TREE_CODE (t))
+ {
+ case COMPOUND_EXPR:
+ case MODIFY_EXPR:
+ case BIND_EXPR:
+ return RECURSE (TREE_OPERAND (t, 1));
+
+ case SAVE_EXPR:
+ return RECURSE (TREE_OPERAND (t, 0));
+
+ default:
+ break;
+ }
+ return false;
+}
+
+#undef RECURSE
+#undef integer_valued_real_p
+
+/* Return true if the floating point expression T has an integer value.
+ We also allow +Inf, -Inf and NaN to be considered integer values.
+
+ DEPTH is the current nesting depth of the query. */
+
+bool
+integer_valued_real_p (tree t, int depth)
+{
+ if (t == error_mark_node)
+ return false;
+
+ tree_code code = TREE_CODE (t);
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_binary:
+ case tcc_comparison:
+ return integer_valued_real_binary_p (code, TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1), depth);
+
+ case tcc_unary:
+ return integer_valued_real_unary_p (code, TREE_OPERAND (t, 0), depth);
+
+ case tcc_constant:
+ case tcc_declaration:
+ case tcc_reference:
+ return integer_valued_real_single_p (t, depth);
+
+ default:
+ break;
+ }
+
+ switch (code)
+ {
+ case COND_EXPR:
+ case SSA_NAME:
+ return integer_valued_real_single_p (t, depth);
+
+ case CALL_EXPR:
+ {
+ tree arg0 = (call_expr_nargs (t) > 0
+ ? CALL_EXPR_ARG (t, 0)
+ : NULL_TREE);
+ tree arg1 = (call_expr_nargs (t) > 1
+ ? CALL_EXPR_ARG (t, 1)
+ : NULL_TREE);
+ return integer_valued_real_call_p (get_callee_fndecl (t),
+ arg0, arg1, depth);
+ }
+
+ default:
+ return integer_valued_real_invalid_p (t, depth);
+ }
+}
+
/* Given the components of a binary expression CODE, TYPE, OP0 and OP1,
attempt to fold the expression to a constant without modifying TYPE,
OP0 or OP1.
if (code == LE_EXPR || code == GT_EXPR)
{
- tree tem = op0;
- op0 = op1;
- op1 = tem;
+ std::swap (op0, op1);
code = swap_tree_comparison (code);
}
return value;
overflow_p = TREE_OVERFLOW (value);
- val &= ~(divisor - 1);
- val += divisor;
+ val += divisor - 1;
+ val &= - (int) divisor;
if (val == 0)
overflow_p = true;
t = build_int_cst (TREE_TYPE (value), divisor - 1);
value = size_binop_loc (loc, PLUS_EXPR, value, t);
- t = build_int_cst (TREE_TYPE (value), -divisor);
+ t = build_int_cst (TREE_TYPE (value), - (int) divisor);
value = size_binop_loc (loc, BIT_AND_EXPR, value, t);
}
}
return true;
}
-/* Simplify the floating point expression EXP when the sign of the
- result is not significant. Return NULL_TREE if no simplification
- is possible. */
-
+/* Return OFF converted to a pointer offset type suitable as offset for
+ POINTER_PLUS_EXPR. Use location LOC for this conversion. */
tree
-fold_strip_sign_ops (tree exp)
+convert_to_ptrofftype_loc (location_t loc, tree off)
{
- tree arg0, arg1;
- location_t loc = EXPR_LOCATION (exp);
-
- switch (TREE_CODE (exp))
- {
- case ABS_EXPR:
- case NEGATE_EXPR:
- arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 0));
- return arg0 ? arg0 : TREE_OPERAND (exp, 0);
-
- case MULT_EXPR:
- case RDIV_EXPR:
- if (HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (exp)))
- return NULL_TREE;
- arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 0));
- arg1 = fold_strip_sign_ops (TREE_OPERAND (exp, 1));
- if (arg0 != NULL_TREE || arg1 != NULL_TREE)
- return fold_build2_loc (loc, TREE_CODE (exp), TREE_TYPE (exp),
- arg0 ? arg0 : TREE_OPERAND (exp, 0),
- arg1 ? arg1 : TREE_OPERAND (exp, 1));
- break;
-
- case COMPOUND_EXPR:
- arg0 = TREE_OPERAND (exp, 0);
- arg1 = fold_strip_sign_ops (TREE_OPERAND (exp, 1));
- if (arg1)
- return fold_build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (exp), arg0, arg1);
- break;
-
- case COND_EXPR:
- arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 1));
- arg1 = fold_strip_sign_ops (TREE_OPERAND (exp, 2));
- if (arg0 || arg1)
- return fold_build3_loc (loc,
- COND_EXPR, TREE_TYPE (exp), TREE_OPERAND (exp, 0),
- arg0 ? arg0 : TREE_OPERAND (exp, 1),
- arg1 ? arg1 : TREE_OPERAND (exp, 2));
- break;
-
- case CALL_EXPR:
- {
- const enum built_in_function fcode = builtin_mathfn_code (exp);
- switch (fcode)
- {
- CASE_FLT_FN (BUILT_IN_COPYSIGN):
- /* Strip copysign function call, return the 1st argument. */
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- return omit_one_operand_loc (loc, TREE_TYPE (exp), arg0, arg1);
+ return fold_convert_loc (loc, sizetype, off);
+}
- default:
- /* Strip sign ops from the argument of "odd" math functions. */
- if (negate_mathfn_p (fcode))
- {
- arg0 = fold_strip_sign_ops (CALL_EXPR_ARG (exp, 0));
- if (arg0)
- return build_call_expr_loc (loc, get_callee_fndecl (exp), 1, arg0);
- }
- break;
- }
- }
- break;
+/* Build and fold a POINTER_PLUS_EXPR at LOC offsetting PTR by OFF. */
+tree
+fold_build_pointer_plus_loc (location_t loc, tree ptr, tree off)
+{
+ return fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (ptr),
+ ptr, convert_to_ptrofftype_loc (loc, off));
+}
- default:
- break;
- }
- return NULL_TREE;
+/* Build and fold a POINTER_PLUS_EXPR at LOC offsetting PTR by OFF. */
+tree
+fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE_INT off)
+{
+ return fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (ptr),
+ ptr, size_int (off));
}