| /* Fold a constant sub-tree into a single node for C-compiler |
| Copyright (C) 1987-2021 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /*@@ This file should be rewritten to use an arbitrary precision |
| @@ representation for "struct tree_int_cst" and "struct tree_real_cst". |
| @@ Perhaps the routines could also be used for bc/dc, and made a lib. |
| @@ The routines that translate from the ap rep should |
| @@ warn if precision et. al. is lost. |
| @@ This would also make life easier when this technology is used |
| @@ for cross-compilers. */ |
| |
| /* The entry points in this file are fold, size_int_wide and size_binop. |
| |
| fold takes a tree as argument and returns a simplified tree. |
| |
| size_binop takes a tree code for an arithmetic operation |
| and two operands that are trees, and produces a tree for the |
| result, assuming the type comes from `sizetype'. |
| |
| size_int takes an integer value, and creates a tree constant |
| with type from `sizetype'. |
| |
| Note: Since the folders get called on non-gimple code as well as |
| gimple code, we need to handle GIMPLE tuples as well as their |
| corresponding tree equivalents. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "backend.h" |
| #include "target.h" |
| #include "rtl.h" |
| #include "tree.h" |
| #include "gimple.h" |
| #include "predict.h" |
| #include "memmodel.h" |
| #include "tm_p.h" |
| #include "tree-ssa-operands.h" |
| #include "optabs-query.h" |
| #include "cgraph.h" |
| #include "diagnostic-core.h" |
| #include "flags.h" |
| #include "alias.h" |
| #include "fold-const.h" |
| #include "fold-const-call.h" |
| #include "stor-layout.h" |
| #include "calls.h" |
| #include "tree-iterator.h" |
| #include "expr.h" |
| #include "intl.h" |
| #include "langhooks.h" |
| #include "tree-eh.h" |
| #include "gimplify.h" |
| #include "tree-dfa.h" |
| #include "builtins.h" |
| #include "generic-match.h" |
| #include "gimple-fold.h" |
| #include "tree-into-ssa.h" |
| #include "md5.h" |
| #include "case-cfn-macros.h" |
| #include "stringpool.h" |
| #include "tree-vrp.h" |
| #include "tree-ssanames.h" |
| #include "selftest.h" |
| #include "stringpool.h" |
| #include "attribs.h" |
| #include "tree-vector-builder.h" |
| #include "vec-perm-indices.h" |
| #include "asan.h" |
| #include "gimple-range.h" |
| |
| /* Nonzero if we are folding constants inside an initializer; zero |
| otherwise. */ |
| int folding_initializer = 0; |
| |
| /* The following constants represent a bit based encoding of GCC's |
| comparison operators. This encoding simplifies transformations |
| on relational comparison operators, such as AND and OR. */ |
| enum comparison_code { |
| COMPCODE_FALSE = 0, |
| COMPCODE_LT = 1, |
| COMPCODE_EQ = 2, |
| COMPCODE_LE = 3, |
| COMPCODE_GT = 4, |
| COMPCODE_LTGT = 5, |
| COMPCODE_GE = 6, |
| COMPCODE_ORD = 7, |
| COMPCODE_UNORD = 8, |
| COMPCODE_UNLT = 9, |
| COMPCODE_UNEQ = 10, |
| COMPCODE_UNLE = 11, |
| COMPCODE_UNGT = 12, |
| COMPCODE_NE = 13, |
| COMPCODE_UNGE = 14, |
| COMPCODE_TRUE = 15 |
| }; |
| |
| static bool negate_expr_p (tree); |
| static tree negate_expr (tree); |
| static tree associate_trees (location_t, tree, tree, enum tree_code, tree); |
| static enum comparison_code comparison_to_compcode (enum tree_code); |
| static enum tree_code compcode_to_comparison (enum comparison_code); |
| static bool twoval_comparison_p (tree, tree *, tree *); |
| static tree eval_subst (location_t, tree, tree, tree, tree, tree); |
| static tree optimize_bit_field_compare (location_t, enum tree_code, |
| tree, tree, tree); |
| static bool simple_operand_p (const_tree); |
| static bool simple_operand_p_2 (tree); |
| static tree range_binop (enum tree_code, tree, tree, int, tree, int); |
| static tree range_predecessor (tree); |
| static tree range_successor (tree); |
| static tree fold_range_test (location_t, enum tree_code, tree, tree, tree); |
| static tree fold_cond_expr_with_comparison (location_t, tree, enum tree_code, |
| tree, tree, tree, tree); |
| static tree unextend (tree, int, int, tree); |
| static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); |
| static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *); |
| static tree fold_binary_op_with_conditional_arg (location_t, |
| enum tree_code, tree, |
| tree, tree, |
| tree, tree, int); |
| static tree fold_negate_const (tree, tree); |
| static tree fold_not_const (const_tree, tree); |
| static tree fold_relational_const (enum tree_code, tree, tree, tree); |
| static tree fold_convert_const (enum tree_code, tree, tree); |
| static tree fold_view_convert_expr (tree, tree); |
| static tree fold_negate_expr (location_t, tree); |
| |
| |
| /* Return EXPR_LOCATION of T if it is not UNKNOWN_LOCATION. |
| Otherwise, return LOC. */ |
| |
| static location_t |
| expr_location_or (tree t, location_t loc) |
| { |
| location_t tloc = EXPR_LOCATION (t); |
| return tloc == UNKNOWN_LOCATION ? loc : tloc; |
| } |
| |
| /* Similar to protected_set_expr_location, but never modify x in place, |
| if location can and needs to be set, unshare it. */ |
| |
| static inline tree |
| protected_set_expr_location_unshare (tree x, location_t loc) |
| { |
| if (CAN_HAVE_LOCATION_P (x) |
| && EXPR_LOCATION (x) != loc |
| && !(TREE_CODE (x) == SAVE_EXPR |
| || TREE_CODE (x) == TARGET_EXPR |
| || TREE_CODE (x) == BIND_EXPR)) |
| { |
| x = copy_node (x); |
| SET_EXPR_LOCATION (x, loc); |
| } |
| return x; |
| } |
| |
| /* If ARG2 divides ARG1 with zero remainder, carries out the exact |
| division and returns the quotient. Otherwise returns |
| NULL_TREE. */ |
| |
| tree |
| div_if_zero_remainder (const_tree arg1, const_tree arg2) |
| { |
| widest_int quo; |
| |
| if (wi::multiple_of_p (wi::to_widest (arg1), wi::to_widest (arg2), |
| SIGNED, &quo)) |
| return wide_int_to_tree (TREE_TYPE (arg1), quo); |
| |
| return NULL_TREE; |
| } |
| |
| /* This is nonzero if we should defer warnings about undefined |
| overflow. This facility exists because these warnings are a |
| special case. The code to estimate loop iterations does not want |
| to issue any warnings, since it works with expressions which do not |
| occur in user code. Various bits of cleanup code call fold(), but |
| only use the result if it has certain characteristics (e.g., is a |
| constant); that code only wants to issue a warning if the result is |
| used. */ |
| |
| static int fold_deferring_overflow_warnings; |
| |
| /* If a warning about undefined overflow is deferred, this is the |
| warning. Note that this may cause us to turn two warnings into |
| one, but that is fine since it is sufficient to only give one |
| warning per expression. */ |
| |
| static const char* fold_deferred_overflow_warning; |
| |
| /* If a warning about undefined overflow is deferred, this is the |
| level at which the warning should be emitted. */ |
| |
| static enum warn_strict_overflow_code fold_deferred_overflow_code; |
| |
| /* Start deferring overflow warnings. We could use a stack here to |
| permit nested calls, but at present it is not necessary. */ |
| |
| void |
| fold_defer_overflow_warnings (void) |
| { |
| ++fold_deferring_overflow_warnings; |
| } |
| |
| /* Stop deferring overflow warnings. If there is a pending warning, |
| and ISSUE is true, then issue the warning if appropriate. STMT is |
| the statement with which the warning should be associated (used for |
| location information); STMT may be NULL. CODE is the level of the |
| warning--a warn_strict_overflow_code value. This function will use |
| the smaller of CODE and the deferred code when deciding whether to |
| issue the warning. CODE may be zero to mean to always use the |
| deferred code. */ |
| |
| void |
| fold_undefer_overflow_warnings (bool issue, const gimple *stmt, int code) |
| { |
| const char *warnmsg; |
| location_t locus; |
| |
| gcc_assert (fold_deferring_overflow_warnings > 0); |
| --fold_deferring_overflow_warnings; |
| if (fold_deferring_overflow_warnings > 0) |
| { |
| if (fold_deferred_overflow_warning != NULL |
| && code != 0 |
| && code < (int) fold_deferred_overflow_code) |
| fold_deferred_overflow_code = (enum warn_strict_overflow_code) code; |
| return; |
| } |
| |
| warnmsg = fold_deferred_overflow_warning; |
| fold_deferred_overflow_warning = NULL; |
| |
| if (!issue || warnmsg == NULL) |
| return; |
| |
| if (warning_suppressed_p (stmt, OPT_Wstrict_overflow)) |
| return; |
| |
| /* Use the smallest code level when deciding to issue the |
| warning. */ |
| if (code == 0 || code > (int) fold_deferred_overflow_code) |
| code = fold_deferred_overflow_code; |
| |
| if (!issue_strict_overflow_warning (code)) |
| return; |
| |
| if (stmt == NULL) |
| locus = input_location; |
| else |
| locus = gimple_location (stmt); |
| warning_at (locus, OPT_Wstrict_overflow, "%s", warnmsg); |
| } |
| |
| /* Stop deferring overflow warnings, ignoring any deferred |
| warnings. */ |
| |
| void |
| fold_undefer_and_ignore_overflow_warnings (void) |
| { |
| fold_undefer_overflow_warnings (false, NULL, 0); |
| } |
| |
| /* Whether we are deferring overflow warnings. */ |
| |
| bool |
| fold_deferring_overflow_warnings_p (void) |
| { |
| return fold_deferring_overflow_warnings > 0; |
| } |
| |
| /* This is called when we fold something based on the fact that signed |
| overflow is undefined. */ |
| |
| void |
| fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code wc) |
| { |
| if (fold_deferring_overflow_warnings > 0) |
| { |
| if (fold_deferred_overflow_warning == NULL |
| || wc < fold_deferred_overflow_code) |
| { |
| fold_deferred_overflow_warning = gmsgid; |
| fold_deferred_overflow_code = wc; |
| } |
| } |
| else if (issue_strict_overflow_warning (wc)) |
| warning (OPT_Wstrict_overflow, gmsgid); |
| } |
| |
| /* Return true if the built-in mathematical function specified by CODE |
| is odd, i.e. -f(x) == f(-x). */ |
| |
| bool |
| negate_mathfn_p (combined_fn fn) |
| { |
| switch (fn) |
| { |
| CASE_CFN_ASIN: |
| CASE_CFN_ASINH: |
| CASE_CFN_ATAN: |
| CASE_CFN_ATANH: |
| CASE_CFN_CASIN: |
| CASE_CFN_CASINH: |
| CASE_CFN_CATAN: |
| CASE_CFN_CATANH: |
| CASE_CFN_CBRT: |
| CASE_CFN_CPROJ: |
| CASE_CFN_CSIN: |
| CASE_CFN_CSINH: |
| CASE_CFN_CTAN: |
| CASE_CFN_CTANH: |
| CASE_CFN_ERF: |
| CASE_CFN_LLROUND: |
| CASE_CFN_LROUND: |
| CASE_CFN_ROUND: |
| CASE_CFN_ROUNDEVEN: |
| CASE_CFN_ROUNDEVEN_FN: |
| CASE_CFN_SIN: |
| CASE_CFN_SINH: |
| CASE_CFN_TAN: |
| CASE_CFN_TANH: |
| CASE_CFN_TRUNC: |
| return true; |
| |
| CASE_CFN_LLRINT: |
| CASE_CFN_LRINT: |
| CASE_CFN_NEARBYINT: |
| CASE_CFN_RINT: |
| return !flag_rounding_math; |
| |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| /* Check whether we may negate an integer constant T without causing |
| overflow. */ |
| |
| bool |
| may_negate_without_overflow_p (const_tree t) |
| { |
| tree type; |
| |
| gcc_assert (TREE_CODE (t) == INTEGER_CST); |
| |
| type = TREE_TYPE (t); |
| if (TYPE_UNSIGNED (type)) |
| return false; |
| |
| return !wi::only_sign_bit_p (wi::to_wide (t)); |
| } |
| |
| /* Determine whether an expression T can be cheaply negated using |
| the function negate_expr without introducing undefined overflow. */ |
| |
| static bool |
| negate_expr_p (tree t) |
| { |
| tree type; |
| |
| if (t == 0) |
| return false; |
| |
| type = TREE_TYPE (t); |
| |
| STRIP_SIGN_NOPS (t); |
| switch (TREE_CODE (t)) |
| { |
| case INTEGER_CST: |
| if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)) |
| return true; |
| |
| /* Check that -CST will not overflow type. */ |
| return may_negate_without_overflow_p (t); |
| case BIT_NOT_EXPR: |
| return (INTEGRAL_TYPE_P (type) |
| && TYPE_OVERFLOW_WRAPS (type)); |
| |
| case FIXED_CST: |
| return true; |
| |
| case NEGATE_EXPR: |
| return !TYPE_OVERFLOW_SANITIZED (type); |
| |
| case REAL_CST: |
| /* We want to canonicalize to positive real constants. Pretend |
| that only negative ones can be easily negated. */ |
| return REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)); |
| |
| case COMPLEX_CST: |
| return negate_expr_p (TREE_REALPART (t)) |
| && negate_expr_p (TREE_IMAGPART (t)); |
| |
| case VECTOR_CST: |
| { |
| if (FLOAT_TYPE_P (TREE_TYPE (type)) || TYPE_OVERFLOW_WRAPS (type)) |
| return true; |
| |
| /* Steps don't prevent negation. */ |
| unsigned int count = vector_cst_encoded_nelts (t); |
| for (unsigned int i = 0; i < count; ++i) |
| if (!negate_expr_p (VECTOR_CST_ENCODED_ELT (t, i))) |
| return false; |
| |
| return true; |
| } |
| |
| case COMPLEX_EXPR: |
| return negate_expr_p (TREE_OPERAND (t, 0)) |
| && negate_expr_p (TREE_OPERAND (t, 1)); |
| |
| case CONJ_EXPR: |
| return negate_expr_p (TREE_OPERAND (t, 0)); |
| |
| case PLUS_EXPR: |
| if (HONOR_SIGN_DEPENDENT_ROUNDING (type) |
| || HONOR_SIGNED_ZEROS (type) |
| || (ANY_INTEGRAL_TYPE_P (type) |
| && ! TYPE_OVERFLOW_WRAPS (type))) |
| return false; |
| /* -(A + B) -> (-B) - A. */ |
| if (negate_expr_p (TREE_OPERAND (t, 1))) |
| return true; |
| /* -(A + B) -> (-A) - B. */ |
| return negate_expr_p (TREE_OPERAND (t, 0)); |
| |
| case MINUS_EXPR: |
| /* We can't turn -(A-B) into B-A when we honor signed zeros. */ |
| return !HONOR_SIGN_DEPENDENT_ROUNDING (type) |
| && !HONOR_SIGNED_ZEROS (type) |
| && (! ANY_INTEGRAL_TYPE_P (type) |
| || TYPE_OVERFLOW_WRAPS (type)); |
| |
| case MULT_EXPR: |
| if (TYPE_UNSIGNED (type)) |
| break; |
| /* INT_MIN/n * n doesn't overflow while negating one operand it does |
| if n is a (negative) power of two. */ |
| if (INTEGRAL_TYPE_P (TREE_TYPE (t)) |
| && ! TYPE_OVERFLOW_WRAPS (TREE_TYPE (t)) |
| && ! ((TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST |
| && (wi::popcount |
| (wi::abs (wi::to_wide (TREE_OPERAND (t, 0))))) != 1) |
| || (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST |
| && (wi::popcount |
| (wi::abs (wi::to_wide (TREE_OPERAND (t, 1))))) != 1))) |
| break; |
| |
| /* Fall through. */ |
| |
| case RDIV_EXPR: |
| if (! HONOR_SIGN_DEPENDENT_ROUNDING (t)) |
| return negate_expr_p (TREE_OPERAND (t, 1)) |
| || negate_expr_p (TREE_OPERAND (t, 0)); |
| break; |
| |
| case TRUNC_DIV_EXPR: |
| case ROUND_DIV_EXPR: |
| case EXACT_DIV_EXPR: |
| if (TYPE_UNSIGNED (type)) |
| break; |
| /* In general we can't negate A in A / B, because if A is INT_MIN and |
| B is not 1 we change the sign of the result. */ |
| if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST |
| && negate_expr_p (TREE_OPERAND (t, 0))) |
| return true; |
| /* In general we can't negate B in A / B, because if A is INT_MIN and |
| B is 1, we may turn this into INT_MIN / -1 which is undefined |
| and actually traps on some architectures. */ |
| if (! ANY_INTEGRAL_TYPE_P (TREE_TYPE (t)) |
| || TYPE_OVERFLOW_WRAPS (TREE_TYPE (t)) |
| || (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST |
| && ! integer_onep (TREE_OPERAND (t, 1)))) |
| return negate_expr_p (TREE_OPERAND (t, 1)); |
| break; |
| |
| case NOP_EXPR: |
| /* Negate -((double)float) as (double)(-float). */ |
| if (TREE_CODE (type) == REAL_TYPE) |
| { |
| tree tem = strip_float_extensions (t); |
| if (tem != t) |
| return negate_expr_p (tem); |
| } |
| break; |
| |
| case CALL_EXPR: |
| /* Negate -f(x) as f(-x). */ |
| if (negate_mathfn_p (get_call_combined_fn (t))) |
| return negate_expr_p (CALL_EXPR_ARG (t, 0)); |
| break; |
| |
| case RSHIFT_EXPR: |
| /* Optimize -((int)x >> 31) into (unsigned)x >> 31 for int. */ |
| if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) |
| { |
| tree op1 = TREE_OPERAND (t, 1); |
| if (wi::to_wide (op1) == element_precision (type) - 1) |
| return true; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| /* Given T, an expression, return a folded tree for -T or NULL_TREE, if no |
| simplification is possible. |
| If negate_expr_p would return true for T, NULL_TREE will never be |
| returned. */ |
| |
| static tree |
| fold_negate_expr_1 (location_t loc, tree t) |
| { |
| tree type = TREE_TYPE (t); |
| tree tem; |
| |
| switch (TREE_CODE (t)) |
| { |
| /* Convert - (~A) to A + 1. */ |
| case BIT_NOT_EXPR: |
| if (INTEGRAL_TYPE_P (type)) |
| return fold_build2_loc (loc, PLUS_EXPR, type, TREE_OPERAND (t, 0), |
| build_one_cst (type)); |
| break; |
| |
| case INTEGER_CST: |
| tem = fold_negate_const (t, type); |
| if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t) |
| || (ANY_INTEGRAL_TYPE_P (type) |
| && !TYPE_OVERFLOW_TRAPS (type) |
| && TYPE_OVERFLOW_WRAPS (type)) |
| || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0) |
| return tem; |
| break; |
| |
| case POLY_INT_CST: |
| case REAL_CST: |
| case FIXED_CST: |
| tem = fold_negate_const (t, type); |
| return tem; |
| |
| case COMPLEX_CST: |
| { |
| tree rpart = fold_negate_expr (loc, TREE_REALPART (t)); |
| tree ipart = fold_negate_expr (loc, TREE_IMAGPART (t)); |
| if (rpart && ipart) |
| return build_complex (type, rpart, ipart); |
| } |
| break; |
| |
| case VECTOR_CST: |
| { |
| tree_vector_builder elts; |
| elts.new_unary_operation (type, t, true); |
| unsigned int count = elts.encoded_nelts (); |
| for (unsigned int i = 0; i < count; ++i) |
| { |
| tree elt = fold_negate_expr (loc, VECTOR_CST_ELT (t, i)); |
| if (elt == NULL_TREE) |
| return NULL_TREE; |
| elts.quick_push (elt); |
| } |
| |
| return elts.build (); |
| } |
| |
| case COMPLEX_EXPR: |
| if (negate_expr_p (t)) |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, |
| fold_negate_expr (loc, TREE_OPERAND (t, 0)), |
| fold_negate_expr (loc, TREE_OPERAND (t, 1))); |
| break; |
| |
| case CONJ_EXPR: |
| if (negate_expr_p (t)) |
| return fold_build1_loc (loc, CONJ_EXPR, type, |
| fold_negate_expr (loc, TREE_OPERAND (t, 0))); |
| break; |
| |
| case NEGATE_EXPR: |
| if (!TYPE_OVERFLOW_SANITIZED (type)) |
| return TREE_OPERAND (t, 0); |
| break; |
| |
| case PLUS_EXPR: |
| if (!HONOR_SIGN_DEPENDENT_ROUNDING (type) |
| && !HONOR_SIGNED_ZEROS (type)) |
| { |
| /* -(A + B) -> (-B) - A. */ |
| if (negate_expr_p (TREE_OPERAND (t, 1))) |
| { |
| tem = negate_expr (TREE_OPERAND (t, 1)); |
| return fold_build2_loc (loc, MINUS_EXPR, type, |
| tem, TREE_OPERAND (t, 0)); |
| } |
| |
| /* -(A + B) -> (-A) - B. */ |
| if (negate_expr_p (TREE_OPERAND (t, 0))) |
| { |
| tem = negate_expr (TREE_OPERAND (t, 0)); |
| return fold_build2_loc (loc, MINUS_EXPR, type, |
| tem, TREE_OPERAND (t, 1)); |
| } |
| } |
| break; |
| |
| case MINUS_EXPR: |
| /* - (A - B) -> B - A */ |
| if (!HONOR_SIGN_DEPENDENT_ROUNDING (type) |
| && !HONOR_SIGNED_ZEROS (type)) |
| return fold_build2_loc (loc, MINUS_EXPR, type, |
| TREE_OPERAND (t, 1), TREE_OPERAND (t, 0)); |
| break; |
| |
| case MULT_EXPR: |
| if (TYPE_UNSIGNED (type)) |
| break; |
| |
| /* Fall through. */ |
| |
| case RDIV_EXPR: |
| if (! HONOR_SIGN_DEPENDENT_ROUNDING (type)) |
| { |
| tem = TREE_OPERAND (t, 1); |
| if (negate_expr_p (tem)) |
| return fold_build2_loc (loc, TREE_CODE (t), type, |
| TREE_OPERAND (t, 0), negate_expr (tem)); |
| tem = TREE_OPERAND (t, 0); |
| if (negate_expr_p (tem)) |
| return fold_build2_loc (loc, TREE_CODE (t), type, |
| negate_expr (tem), TREE_OPERAND (t, 1)); |
| } |
| break; |
| |
| case TRUNC_DIV_EXPR: |
| case ROUND_DIV_EXPR: |
| case EXACT_DIV_EXPR: |
| if (TYPE_UNSIGNED (type)) |
| break; |
| /* In general we can't negate A in A / B, because if A is INT_MIN and |
| B is not 1 we change the sign of the result. */ |
| if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST |
| && negate_expr_p (TREE_OPERAND (t, 0))) |
| return fold_build2_loc (loc, TREE_CODE (t), type, |
| negate_expr (TREE_OPERAND (t, 0)), |
| TREE_OPERAND (t, 1)); |
| /* In general we can't negate B in A / B, because if A is INT_MIN and |
| B is 1, we may turn this into INT_MIN / -1 which is undefined |
| and actually traps on some architectures. */ |
| if ((! ANY_INTEGRAL_TYPE_P (TREE_TYPE (t)) |
| || TYPE_OVERFLOW_WRAPS (TREE_TYPE (t)) |
| || (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST |
| && ! integer_onep (TREE_OPERAND (t, 1)))) |
| && negate_expr_p (TREE_OPERAND (t, 1))) |
| return fold_build2_loc (loc, TREE_CODE (t), type, |
| TREE_OPERAND (t, 0), |
| negate_expr (TREE_OPERAND (t, 1))); |
| break; |
| |
| case NOP_EXPR: |
| /* Convert -((double)float) into (double)(-float). */ |
| if (TREE_CODE (type) == REAL_TYPE) |
| { |
| tem = strip_float_extensions (t); |
| if (tem != t && negate_expr_p (tem)) |
| return fold_convert_loc (loc, type, negate_expr (tem)); |
| } |
| break; |
| |
| case CALL_EXPR: |
| /* Negate -f(x) as f(-x). */ |
| if (negate_mathfn_p (get_call_combined_fn (t)) |
| && negate_expr_p (CALL_EXPR_ARG (t, 0))) |
| { |
| tree fndecl, arg; |
| |
| fndecl = get_callee_fndecl (t); |
| arg = negate_expr (CALL_EXPR_ARG (t, 0)); |
| return build_call_expr_loc (loc, fndecl, 1, arg); |
| } |
| break; |
| |
| case RSHIFT_EXPR: |
| /* Optimize -((int)x >> 31) into (unsigned)x >> 31 for int. */ |
| if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) |
| { |
| tree op1 = TREE_OPERAND (t, 1); |
| if (wi::to_wide (op1) == element_precision (type) - 1) |
| { |
| tree ntype = TYPE_UNSIGNED (type) |
| ? signed_type_for (type) |
| : unsigned_type_for (type); |
| tree temp = fold_convert_loc (loc, ntype, TREE_OPERAND (t, 0)); |
| temp = fold_build2_loc (loc, RSHIFT_EXPR, ntype, temp, op1); |
| return fold_convert_loc (loc, type, temp); |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* A wrapper for fold_negate_expr_1. */ |
| |
| static tree |
| fold_negate_expr (location_t loc, tree t) |
| { |
| tree type = TREE_TYPE (t); |
| STRIP_SIGN_NOPS (t); |
| tree tem = fold_negate_expr_1 (loc, t); |
| if (tem == NULL_TREE) |
| return NULL_TREE; |
| return fold_convert_loc (loc, type, tem); |
| } |
| |
| /* Like fold_negate_expr, but return a NEGATE_EXPR tree, if T cannot be |
| negated in a simpler way. Also allow for T to be NULL_TREE, in which case |
| return NULL_TREE. */ |
| |
| static tree |
| negate_expr (tree t) |
| { |
| tree type, tem; |
| location_t loc; |
| |
| if (t == NULL_TREE) |
| return NULL_TREE; |
| |
| loc = EXPR_LOCATION (t); |
| type = TREE_TYPE (t); |
| STRIP_SIGN_NOPS (t); |
| |
| tem = fold_negate_expr (loc, t); |
| if (!tem) |
| tem = build1_loc (loc, NEGATE_EXPR, TREE_TYPE (t), t); |
| return fold_convert_loc (loc, type, tem); |
| } |
| |
| /* Split a tree IN into a constant, literal and variable parts that could be |
| combined with CODE to make IN. "constant" means an expression with |
| TREE_CONSTANT but that isn't an actual constant. CODE must be a |
| commutative arithmetic operation. Store the constant part into *CONP, |
| the literal in *LITP and return the variable part. If a part isn't |
| present, set it to null. If the tree does not decompose in this way, |
| return the entire tree as the variable part and the other parts as null. |
| |
| If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. In that |
| case, we negate an operand that was subtracted. Except if it is a |
| literal for which we use *MINUS_LITP instead. |
| |
| If NEGATE_P is true, we are negating all of IN, again except a literal |
| for which we use *MINUS_LITP instead. If a variable part is of pointer |
| type, it is negated after converting to TYPE. This prevents us from |
| generating illegal MINUS pointer expression. LOC is the location of |
| the converted variable part. |
| |
| If IN is itself a literal or constant, return it as appropriate. |
| |
| Note that we do not guarantee that any of the three values will be the |
| same type as IN, but they will have the same signedness and mode. */ |
| |
| static tree |
| split_tree (tree in, tree type, enum tree_code code, |
| tree *minus_varp, tree *conp, tree *minus_conp, |
| tree *litp, tree *minus_litp, int negate_p) |
| { |
| tree var = 0; |
| *minus_varp = 0; |
| *conp = 0; |
| *minus_conp = 0; |
| *litp = 0; |
| *minus_litp = 0; |
| |
| /* Strip any conversions that don't change the machine mode or signedness. */ |
| STRIP_SIGN_NOPS (in); |
| |
| if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST |
| || TREE_CODE (in) == FIXED_CST) |
| *litp = in; |
| else if (TREE_CODE (in) == code |
| || ((! FLOAT_TYPE_P (TREE_TYPE (in)) || flag_associative_math) |
| && ! SAT_FIXED_POINT_TYPE_P (TREE_TYPE (in)) |
| /* We can associate addition and subtraction together (even |
| though the C standard doesn't say so) for integers because |
| the value is not affected. For reals, the value might be |
| affected, so we can't. */ |
| && ((code == PLUS_EXPR && TREE_CODE (in) == POINTER_PLUS_EXPR) |
| || (code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR) |
| || (code == MINUS_EXPR |
| && (TREE_CODE (in) == PLUS_EXPR |
| || TREE_CODE (in) == POINTER_PLUS_EXPR))))) |
| { |
| tree op0 = TREE_OPERAND (in, 0); |
| tree op1 = TREE_OPERAND (in, 1); |
| int neg1_p = TREE_CODE (in) == MINUS_EXPR; |
| int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0; |
| |
| /* First see if either of the operands is a literal, then a constant. */ |
| if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST |
| || TREE_CODE (op0) == FIXED_CST) |
| *litp = op0, op0 = 0; |
| else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST |
| || TREE_CODE (op1) == FIXED_CST) |
| *litp = op1, neg_litp_p = neg1_p, op1 = 0; |
| |
| if (op0 != 0 && TREE_CONSTANT (op0)) |
| *conp = op0, op0 = 0; |
| else if (op1 != 0 && TREE_CONSTANT (op1)) |
| *conp = op1, neg_conp_p = neg1_p, op1 = 0; |
| |
| /* If we haven't dealt with either operand, this is not a case we can |
| decompose. Otherwise, VAR is either of the ones remaining, if any. */ |
| if (op0 != 0 && op1 != 0) |
| var = in; |
| else if (op0 != 0) |
| var = op0; |
| else |
| var = op1, neg_var_p = neg1_p; |
| |
| /* Now do any needed negations. */ |
| if (neg_litp_p) |
| *minus_litp = *litp, *litp = 0; |
| if (neg_conp_p && *conp) |
| *minus_conp = *conp, *conp = 0; |
| if (neg_var_p && var) |
| *minus_varp = var, var = 0; |
| } |
| else if (TREE_CONSTANT (in)) |
| *conp = in; |
| else if (TREE_CODE (in) == BIT_NOT_EXPR |
| && code == PLUS_EXPR) |
| { |
| /* -1 - X is folded to ~X, undo that here. Do _not_ do this |
| when IN is constant. */ |
| *litp = build_minus_one_cst (type); |
| *minus_varp = TREE_OPERAND (in, 0); |
| } |
| else |
| var = in; |
| |
| if (negate_p) |
| { |
| if (*litp) |
| *minus_litp = *litp, *litp = 0; |
| else if (*minus_litp) |
| *litp = *minus_litp, *minus_litp = 0; |
| if (*conp) |
| *minus_conp = *conp, *conp = 0; |
| else if (*minus_conp) |
| *conp = *minus_conp, *minus_conp = 0; |
| if (var) |
| *minus_varp = var, var = 0; |
| else if (*minus_varp) |
| var = *minus_varp, *minus_varp = 0; |
| } |
| |
| if (*litp |
| && TREE_OVERFLOW_P (*litp)) |
| *litp = drop_tree_overflow (*litp); |
| if (*minus_litp |
| && TREE_OVERFLOW_P (*minus_litp)) |
| *minus_litp = drop_tree_overflow (*minus_litp); |
| |
| return var; |
| } |
| |
| /* Re-associate trees split by the above function. T1 and T2 are |
| either expressions to associate or null. Return the new |
| expression, if any. LOC is the location of the new expression. If |
| we build an operation, do it in TYPE and with CODE. */ |
| |
| static tree |
| associate_trees (location_t loc, tree t1, tree t2, enum tree_code code, tree type) |
| { |
| if (t1 == 0) |
| { |
| gcc_assert (t2 == 0 || code != MINUS_EXPR); |
| return t2; |
| } |
| else if (t2 == 0) |
| return t1; |
| |
| /* If either input is CODE, a PLUS_EXPR, or a MINUS_EXPR, don't |
| try to fold this since we will have infinite recursion. But do |
| deal with any NEGATE_EXPRs. */ |
| if (TREE_CODE (t1) == code || TREE_CODE (t2) == code |
| || TREE_CODE (t1) == PLUS_EXPR || TREE_CODE (t2) == PLUS_EXPR |
| || TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR) |
| { |
| if (code == PLUS_EXPR) |
| { |
| if (TREE_CODE (t1) == NEGATE_EXPR) |
| return build2_loc (loc, MINUS_EXPR, type, |
| fold_convert_loc (loc, type, t2), |
| fold_convert_loc (loc, type, |
| TREE_OPERAND (t1, 0))); |
| else if (TREE_CODE (t2) == NEGATE_EXPR) |
| return build2_loc (loc, MINUS_EXPR, type, |
| fold_convert_loc (loc, type, t1), |
| fold_convert_loc (loc, type, |
| TREE_OPERAND (t2, 0))); |
| else if (integer_zerop (t2)) |
| return fold_convert_loc (loc, type, t1); |
| } |
| else if (code == MINUS_EXPR) |
| { |
| if (integer_zerop (t2)) |
| return fold_convert_loc (loc, type, t1); |
| } |
| |
| return build2_loc (loc, code, type, fold_convert_loc (loc, type, t1), |
| fold_convert_loc (loc, type, t2)); |
| } |
| |
| return fold_build2_loc (loc, code, type, fold_convert_loc (loc, type, t1), |
| fold_convert_loc (loc, type, t2)); |
| } |
| |
| /* Check whether TYPE1 and TYPE2 are equivalent integer types, suitable |
| for use in int_const_binop, size_binop and size_diffop. */ |
| |
| static bool |
| int_binop_types_match_p (enum tree_code code, const_tree type1, const_tree type2) |
| { |
| if (!INTEGRAL_TYPE_P (type1) && !POINTER_TYPE_P (type1)) |
| return false; |
| if (!INTEGRAL_TYPE_P (type2) && !POINTER_TYPE_P (type2)) |
| return false; |
| |
| switch (code) |
| { |
| case LSHIFT_EXPR: |
| case RSHIFT_EXPR: |
| case LROTATE_EXPR: |
| case RROTATE_EXPR: |
| return true; |
| |
| default: |
| break; |
| } |
| |
| return TYPE_UNSIGNED (type1) == TYPE_UNSIGNED (type2) |
| && TYPE_PRECISION (type1) == TYPE_PRECISION (type2) |
| && TYPE_MODE (type1) == TYPE_MODE (type2); |
| } |
| |
| /* Combine two wide ints ARG1 and ARG2 under operation CODE to produce |
| a new constant in RES. Return FALSE if we don't know how to |
| evaluate CODE at compile-time. */ |
| |
| bool |
| wide_int_binop (wide_int &res, |
| enum tree_code code, const wide_int &arg1, const wide_int &arg2, |
| signop sign, wi::overflow_type *overflow) |
| { |
| wide_int tmp; |
| *overflow = wi::OVF_NONE; |
| switch (code) |
| { |
| case BIT_IOR_EXPR: |
| res = wi::bit_or (arg1, arg2); |
| break; |
| |
| case BIT_XOR_EXPR: |
| res = wi::bit_xor (arg1, arg2); |
| break; |
| |
| case BIT_AND_EXPR: |
| res = wi::bit_and (arg1, arg2); |
| break; |
| |
| case LSHIFT_EXPR: |
| if (wi::neg_p (arg2)) |
| return false; |
| res = wi::lshift (arg1, arg2); |
| break; |
| |
| case RSHIFT_EXPR: |
| if (wi::neg_p (arg2)) |
| return false; |
| /* It's unclear from the C standard whether shifts can overflow. |
| The following code ignores overflow; perhaps a C standard |
| interpretation ruling is needed. */ |
| res = wi::rshift (arg1, arg2, sign); |
| break; |
| |
| case RROTATE_EXPR: |
| case LROTATE_EXPR: |
| if (wi::neg_p (arg2)) |
| { |
| tmp = -arg2; |
| if (code == RROTATE_EXPR) |
| code = LROTATE_EXPR; |
| else |
| code = RROTATE_EXPR; |
| } |
| else |
| tmp = arg2; |
| |
| if (code == RROTATE_EXPR) |
| res = wi::rrotate (arg1, tmp); |
| else |
| res = wi::lrotate (arg1, tmp); |
| break; |
| |
| case PLUS_EXPR: |
| res = wi::add (arg1, arg2, sign, overflow); |
| break; |
| |
| case MINUS_EXPR: |
| res = wi::sub (arg1, arg2, sign, overflow); |
| break; |
| |
| case MULT_EXPR: |
| res = wi::mul (arg1, arg2, sign, overflow); |
| break; |
| |
| case MULT_HIGHPART_EXPR: |
| res = wi::mul_high (arg1, arg2, sign); |
| break; |
| |
| case TRUNC_DIV_EXPR: |
| case EXACT_DIV_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::div_trunc (arg1, arg2, sign, overflow); |
| break; |
| |
| case FLOOR_DIV_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::div_floor (arg1, arg2, sign, overflow); |
| break; |
| |
| case CEIL_DIV_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::div_ceil (arg1, arg2, sign, overflow); |
| break; |
| |
| case ROUND_DIV_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::div_round (arg1, arg2, sign, overflow); |
| break; |
| |
| case TRUNC_MOD_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::mod_trunc (arg1, arg2, sign, overflow); |
| break; |
| |
| case FLOOR_MOD_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::mod_floor (arg1, arg2, sign, overflow); |
| break; |
| |
| case CEIL_MOD_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::mod_ceil (arg1, arg2, sign, overflow); |
| break; |
| |
| case ROUND_MOD_EXPR: |
| if (arg2 == 0) |
| return false; |
| res = wi::mod_round (arg1, arg2, sign, overflow); |
| break; |
| |
| case MIN_EXPR: |
| res = wi::min (arg1, arg2, sign); |
| break; |
| |
| case MAX_EXPR: |
| res = wi::max (arg1, arg2, sign); |
| break; |
| |
| default: |
| return false; |
| } |
| return true; |
| } |
| |
| /* Combine two poly int's ARG1 and ARG2 under operation CODE to |
| produce a new constant in RES. Return FALSE if we don't know how |
| to evaluate CODE at compile-time. */ |
| |
| static bool |
| poly_int_binop (poly_wide_int &res, enum tree_code code, |
| const_tree arg1, const_tree arg2, |
| signop sign, wi::overflow_type *overflow) |
| { |
| gcc_assert (NUM_POLY_INT_COEFFS != 1); |
| gcc_assert (poly_int_tree_p (arg1) && poly_int_tree_p (arg2)); |
| switch (code) |
| { |
| case PLUS_EXPR: |
| res = wi::add (wi::to_poly_wide (arg1), |
| wi::to_poly_wide (arg2), sign, overflow); |
| break; |
| |
| case MINUS_EXPR: |
| res = wi::sub (wi::to_poly_wide (arg1), |
| wi::to_poly_wide (arg2), sign, overflow); |
| break; |
| |
| case MULT_EXPR: |
| if (TREE_CODE (arg2) == INTEGER_CST) |
| res = wi::mul (wi::to_poly_wide (arg1), |
| wi::to_wide (arg2), sign, overflow); |
| else if (TREE_CODE (arg1) == INTEGER_CST) |
| res = wi::mul (wi::to_poly_wide (arg2), |
| wi::to_wide (arg1), sign, overflow); |
| else |
| return NULL_TREE; |
| break; |
| |
| case LSHIFT_EXPR: |
| if (TREE_CODE (arg2) == INTEGER_CST) |
| res = wi::to_poly_wide (arg1) << wi::to_wide (arg2); |
| else |
| return false; |
| break; |
| |
| case BIT_IOR_EXPR: |
| if (TREE_CODE (arg2) != INTEGER_CST |
| || !can_ior_p (wi::to_poly_wide (arg1), wi::to_wide (arg2), |
| &res)) |
| return false; |
| break; |
| |
| default: |
| return false; |
| } |
| return true; |
| } |
| |
| /* Combine two integer constants ARG1 and ARG2 under operation CODE to |
| produce a new constant. Return NULL_TREE if we don't know how to |
| evaluate CODE at compile-time. */ |
| |
| tree |
| int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2, |
| int overflowable) |
| { |
| poly_wide_int poly_res; |
| tree type = TREE_TYPE (arg1); |
| signop sign = TYPE_SIGN (type); |
| wi::overflow_type overflow = wi::OVF_NONE; |
| |
| if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST) |
| { |
| wide_int warg1 = wi::to_wide (arg1), res; |
| wide_int warg2 = wi::to_wide (arg2, TYPE_PRECISION (type)); |
| if (!wide_int_binop (res, code, warg1, warg2, sign, &overflow)) |
| return NULL_TREE; |
| poly_res = res; |
| } |
| else if (!poly_int_tree_p (arg1) |
| || !poly_int_tree_p (arg2) |
| || !poly_int_binop (poly_res, code, arg1, arg2, sign, &overflow)) |
| return NULL_TREE; |
| return force_fit_type (type, poly_res, overflowable, |
| (((sign == SIGNED || overflowable == -1) |
| && overflow) |
| | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2))); |
| } |
| |
| /* Return true if binary operation OP distributes over addition in operand |
| OPNO, with the other operand being held constant. OPNO counts from 1. */ |
| |
| static bool |
| distributes_over_addition_p (tree_code op, int opno) |
| { |
| switch (op) |
| { |
| case PLUS_EXPR: |
| case MINUS_EXPR: |
| case MULT_EXPR: |
| return true; |
| |
| case LSHIFT_EXPR: |
| return opno == 1; |
| |
| default: |
| return false; |
| } |
| } |
| |
| /* Combine two constants ARG1 and ARG2 under operation CODE to produce a new |
| constant. We assume ARG1 and ARG2 have the same data type, or at least |
| are the same kind of constant and the same machine mode. Return zero if |
| combining the constants is not allowed in the current operating mode. */ |
| |
| static tree |
| const_binop (enum tree_code code, tree arg1, tree arg2) |
| { |
| /* Sanity check for the recursive cases. */ |
| if (!arg1 || !arg2) |
| return NULL_TREE; |
| |
| STRIP_NOPS (arg1); |
| STRIP_NOPS (arg2); |
| |
| if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2)) |
| { |
| if (code == POINTER_PLUS_EXPR) |
| return int_const_binop (PLUS_EXPR, |
| arg1, fold_convert (TREE_TYPE (arg1), arg2)); |
| |
| return int_const_binop (code, arg1, arg2); |
| } |
| |
| if (TREE_CODE (arg1) == REAL_CST && TREE_CODE (arg2) == REAL_CST) |
| { |
| machine_mode mode; |
| REAL_VALUE_TYPE d1; |
| REAL_VALUE_TYPE d2; |
| REAL_VALUE_TYPE value; |
| REAL_VALUE_TYPE result; |
| bool inexact; |
| tree t, type; |
| |
| /* The following codes are handled by real_arithmetic. */ |
| switch (code) |
| { |
| case PLUS_EXPR: |
| case MINUS_EXPR: |
| case MULT_EXPR: |
| case RDIV_EXPR: |
| case MIN_EXPR: |
| case MAX_EXPR: |
| break; |
| |
| default: |
| return NULL_TREE; |
| } |
| |
| d1 = TREE_REAL_CST (arg1); |
| d2 = TREE_REAL_CST (arg2); |
| |
| type = TREE_TYPE (arg1); |
| mode = TYPE_MODE (type); |
| |
| /* Don't perform operation if we honor signaling NaNs and |
| either operand is a signaling NaN. */ |
| if (HONOR_SNANS (mode) |
| && (REAL_VALUE_ISSIGNALING_NAN (d1) |
| || REAL_VALUE_ISSIGNALING_NAN (d2))) |
| return NULL_TREE; |
| |
| /* Don't perform operation if it would raise a division |
| by zero exception. */ |
| if (code == RDIV_EXPR |
| && real_equal (&d2, &dconst0) |
| && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode))) |
| return NULL_TREE; |
| |
| /* If either operand is a NaN, just return it. Otherwise, set up |
| for floating-point trap; we return an overflow. */ |
| if (REAL_VALUE_ISNAN (d1)) |
| { |
| /* Make resulting NaN value to be qNaN when flag_signaling_nans |
| is off. */ |
| d1.signalling = 0; |
| t = build_real (type, d1); |
| return t; |
| } |
| else if (REAL_VALUE_ISNAN (d2)) |
| { |
| /* Make resulting NaN value to be qNaN when flag_signaling_nans |
| is off. */ |
| d2.signalling = 0; |
| t = build_real (type, d2); |
| return t; |
| } |
| |
| inexact = real_arithmetic (&value, code, &d1, &d2); |
| real_convert (&result, mode, &value); |
| |
| /* Don't constant fold this floating point operation if |
| the result has overflowed and flag_trapping_math. */ |
| if (flag_trapping_math |
| && MODE_HAS_INFINITIES (mode) |
| && REAL_VALUE_ISINF (result) |
| && !REAL_VALUE_ISINF (d1) |
| && !REAL_VALUE_ISINF (d2)) |
| return NULL_TREE; |
| |
| /* Don't constant fold this floating point operation if the |
| result may dependent upon the run-time rounding mode and |
| flag_rounding_math is set, or if GCC's software emulation |
| is unable to accurately represent the result. */ |
| if ((flag_rounding_math |
| || (MODE_COMPOSITE_P (mode) && !flag_unsafe_math_optimizations)) |
| && (inexact || !real_identical (&result, &value))) |
| return NULL_TREE; |
| |
| t = build_real (type, result); |
| |
| TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2); |
| return t; |
| } |
| |
| if (TREE_CODE (arg1) == FIXED_CST) |
| { |
| FIXED_VALUE_TYPE f1; |
| FIXED_VALUE_TYPE f2; |
| FIXED_VALUE_TYPE result; |
| tree t, type; |
| int sat_p; |
| bool overflow_p; |
| |
| /* The following codes are handled by fixed_arithmetic. */ |
| switch (code) |
| { |
| case PLUS_EXPR: |
| case MINUS_EXPR: |
| case MULT_EXPR: |
| case TRUNC_DIV_EXPR: |
| if (TREE_CODE (arg2) != FIXED_CST) |
| return NULL_TREE; |
| f2 = TREE_FIXED_CST (arg2); |
| break; |
| |
| case LSHIFT_EXPR: |
| case RSHIFT_EXPR: |
| { |
| if (TREE_CODE (arg2) != INTEGER_CST) |
| return NULL_TREE; |
| wi::tree_to_wide_ref w2 = wi::to_wide (arg2); |
| f2.data.high = w2.elt (1); |
| f2.data.low = w2.ulow (); |
| f2.mode = SImode; |
| } |
| break; |
| |
| default: |
| return NULL_TREE; |
| } |
| |
| f1 = TREE_FIXED_CST (arg1); |
| type = TREE_TYPE (arg1); |
| sat_p = TYPE_SATURATING (type); |
| overflow_p = fixed_arithmetic (&result, code, &f1, &f2, sat_p); |
| t = build_fixed (type, result); |
| /* Propagate overflow flags. */ |
| if (overflow_p | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)) |
| TREE_OVERFLOW (t) = 1; |
| return t; |
| } |
| |
| if (TREE_CODE (arg1) == COMPLEX_CST && TREE_CODE (arg2) == COMPLEX_CST) |
| { |
| tree type = TREE_TYPE (arg1); |
| tree r1 = TREE_REALPART (arg1); |
| tree i1 = TREE_IMAGPART (arg1); |
| tree r2 = TREE_REALPART (arg2); |
| tree i2 = TREE_IMAGPART (arg2); |
| tree real, imag; |
| |
| switch (code) |
| { |
| case PLUS_EXPR: |
| case MINUS_EXPR: |
| real = const_binop (code, r1, r2); |
| imag = const_binop (code, i1, i2); |
| break; |
| |
| case MULT_EXPR: |
| if (COMPLEX_FLOAT_TYPE_P (type)) |
| return do_mpc_arg2 (arg1, arg2, type, |
| /* do_nonfinite= */ folding_initializer, |
| mpc_mul); |
| |
| real = const_binop (MINUS_EXPR, |
| const_binop (MULT_EXPR, r1, r2), |
| const_binop (MULT_EXPR, i1, i2)); |
| imag = const_binop (PLUS_EXPR, |
| const_binop (MULT_EXPR, r1, i2), |
| const_binop (MULT_EXPR, i1, r2)); |
| break; |
| |
| case RDIV_EXPR: |
| if (COMPLEX_FLOAT_TYPE_P (type)) |
| return do_mpc_arg2 (arg1, arg2, type, |
| /* do_nonfinite= */ folding_initializer, |
| mpc_div); |
| /* Fallthru. */ |
| case TRUNC_DIV_EXPR: |
| case CEIL_DIV_EXPR: |
| case FLOOR_DIV_EXPR: |
| case ROUND_DIV_EXPR: |
| if (flag_complex_method == 0) |
| { |
| /* Keep this algorithm in sync with |
| tree-complex.c:expand_complex_div_straight(). |
| |
| Expand complex division to scalars, straightforward algorithm. |
| a / b = ((ar*br + ai*bi)/t) + i((ai*br - ar*bi)/t) |
| t = br*br + bi*bi |
| */ |
| tree magsquared |
| = const_binop (PLUS_EXPR, |
| const_binop (MULT_EXPR, r2, r2), |
| const_binop (MULT_EXPR, i2, i2)); |
| tree t1 |
| = const_binop (PLUS_EXPR, |
| const_binop (MULT_EXPR, r1, r2), |
| const_binop (MULT_EXPR, i1, i2)); |
| tree t2 |
| = const_binop (MINUS_EXPR, |
| const_binop (MULT_EXPR, i1, r2), |
| const_binop (MULT_EXPR, r1, i2)); |
| |
| real = const_binop (code, t1, magsquared); |
| imag = const_binop (code, t2, magsquared); |
| } |
| else |
| { |
| /* Keep this algorithm in sync with |
| tree-complex.c:expand_complex_div_wide(). |
| |
| Expand complex division to scalars, modified algorithm to minimize |
| overflow with wide input ranges. */ |
| tree compare = fold_build2 (LT_EXPR, boolean_type_node, |
| fold_abs_const (r2, TREE_TYPE (type)), |
| fold_abs_const (i2, TREE_TYPE (type))); |
| |
| if (integer_nonzerop (compare)) |
| { |
| /* In the TRUE branch, we compute |
| ratio = br/bi; |
| div = (br * ratio) + bi; |
| tr = (ar * ratio) + ai; |
| ti = (ai * ratio) - ar; |
| tr = tr / div; |
| ti = ti / div; */ |
| tree ratio = const_binop (code, r2, i2); |
| tree div = const_binop (PLUS_EXPR, i2, |
| const_binop (MULT_EXPR, r2, ratio)); |
| real = const_binop (MULT_EXPR, r1, ratio); |
| real = const_binop (PLUS_EXPR, real, i1); |
| real = const_binop (code, real, div); |
| |
| imag = const_binop (MULT_EXPR, i1, ratio); |
| imag = const_binop (MINUS_EXPR, imag, r1); |
| imag = const_binop (code, imag, div); |
| } |
| else |
| { |
| /* In the FALSE branch, we compute |
| ratio = d/c; |
| divisor = (d * ratio) + c; |
| tr = (b * ratio) + a; |
| ti = b - (a * ratio); |
| tr = tr / div; |
| ti = ti / div; */ |
| tree ratio = const_binop (code, i2, r2); |
| tree div = const_binop (PLUS_EXPR, r2, |
| const_binop (MULT_EXPR, i2, ratio)); |
| |
| real = const_binop (MULT_EXPR, i1, ratio); |
| real = const_binop (PLUS_EXPR, real, r1); |
| real = const_binop (code, real, div); |
| |
| imag = const_binop (MULT_EXPR, r1, ratio); |
| imag = const_binop (MINUS_EXPR, i1, imag); |
| imag = const_binop (code, imag, div); |
| } |
| } |
| break; |
| |
| default: |
| return NULL_TREE; |
| } |
| |
| if (real && imag) |
| return build_complex (type, real, imag); |
| } |
| |
| if (TREE_CODE (arg1) == VECTOR_CST |
| && TREE_CODE (arg2) == VECTOR_CST |
| && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)), |
| TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg2)))) |
| { |
| tree type = TREE_TYPE (arg1); |
| bool step_ok_p; |
| if (VECTOR_CST_STEPPED_P (arg1) |
| && VECTOR_CST_STEPPED_P (arg2)) |
| /* We can operate directly on the encoding if: |
| |
| a3 - a2 == a2 - a1 && b3 - b2 == b2 - b1 |
| implies |
| (a3 op b3) - (a2 op b2) == (a2 op b2) - (a1 op b1) |
| |
| Addition and subtraction are the supported operators |
| for which this is true. */ |
| step_ok_p = (code == PLUS_EXPR || code == MINUS_EXPR); |
| else if (VECTOR_CST_STEPPED_P (arg1)) |
| /* We can operate directly on stepped encodings if: |
| |
| a3 - a2 == a2 - a1 |
| implies: |
| (a3 op c) - (a2 op c) == (a2 op c) - (a1 op c) |
| |
| which is true if (x -> x op c) distributes over addition. */ |
| step_ok_p = distributes_over_addition_p (code, 1); |
| else |
| /* Similarly in reverse. */ |
| step_ok_p = distributes_over_addition_p (code, 2); |
| tree_vector_builder elts; |
| if (!elts.new_binary_operation (type, arg1, arg2, step_ok_p)) |
| return NULL_TREE; |
| unsigned int count = elts.encoded_nelts (); |
| for (unsigned int i = 0; i < count; ++i) |
| { |
| tree elem1 = VECTOR_CST_ELT (arg1, i); |
| tree elem2 = VECTOR_CST_ELT (arg2, i); |
| |
| tree elt = const_binop (code, elem1, elem2); |
| |
| /* It is possible that const_binop cannot handle the given |
| code and return NULL_TREE */ |
| if (elt == NULL_TREE) |
| return NULL_TREE; |
| elts.quick_push (elt); |
| } |
| |
| return elts.build (); |
| } |
| |
| /* Shifts allow a scalar offset for a vector. */ |
| if (TREE_CODE (arg1) == VECTOR_CST |
| && TREE_CODE (arg2) == INTEGER_CST) |
| { |
| tree type = TREE_TYPE (arg1); |
| bool step_ok_p = distributes_over_addition_p (code, 1); |
| tree_vector_builder elts; |
| if (!elts.new_unary_operation (type, arg1, step_ok_p)) |
| return NULL_TREE; |
| unsigned int count = elts.encoded_nelts (); |
| for (unsigned int i = 0; i < count; ++i) |
| { |
| tree elem1 = VECTOR_CST_ELT (arg1, i); |
| |
| tree elt = const_binop (code, elem1, arg2); |
| |
| /* It is possible that const_binop cannot handle the given |
| code and return NULL_TREE. */ |
| if (elt == NULL_TREE) |
| return NULL_TREE; |
| elts.quick_push (elt); |
| } |
| |
| return elts.build (); |
| } |
| return NULL_TREE; |
| } |
| |
| /* Overload that adds a TYPE parameter to be able to dispatch |
| to fold_relational_const. */ |
| |
| tree |
| const_binop (enum tree_code code, tree type, tree arg1, tree arg2) |
| { |
| if (TREE_CODE_CLASS (code) == tcc_comparison) |
| return fold_relational_const (code, type, arg1, arg2); |
| |
| /* ??? Until we make the const_binop worker take the type of the |
| result as argument put those cases that need it here. */ |
| switch (code) |
| { |
| case VEC_SERIES_EXPR: |
| if (CONSTANT_CLASS_P (arg1) |
| && CONSTANT_CLASS_P (arg2)) |
| return build_vec_series (type, arg1, arg2); |
| return NULL_TREE; |
| |
| case COMPLEX_EXPR: |
| if ((TREE_CODE (arg1) == REAL_CST |
| && TREE_CODE (arg2) == REAL_CST) |
| || (TREE_CODE (arg1) == INTEGER_CST |
| && TREE_CODE (arg2) == INTEGER_CST)) |
| return build_complex (type, arg1, arg2); |
| return NULL_TREE; |
| |
| case POINTER_DIFF_EXPR: |
| if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2)) |
| { |
| poly_offset_int res = (wi::to_poly_offset (arg1) |
| - wi::to_poly_offset (arg2)); |
| return force_fit_type (type, res, 1, |
| TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)); |
| } |
| return NULL_TREE; |
| |
| case VEC_PACK_TRUNC_EXPR: |
| case VEC_PACK_FIX_TRUNC_EXPR: |
| case VEC_PACK_FLOAT_EXPR: |
| { |
| unsigned int HOST_WIDE_INT out_nelts, in_nelts, i; |
| |
| if (TREE_CODE (arg1) != VECTOR_CST |
| || TREE_CODE (arg2) != VECTOR_CST) |
| return NULL_TREE; |
| |
| if (!VECTOR_CST_NELTS (arg1).is_constant (&in_nelts)) |
| return NULL_TREE; |
| |
| out_nelts = in_nelts * 2; |
| gcc_assert (known_eq (in_nelts, VECTOR_CST_NELTS (arg2)) |
| && known_eq (out_nelts, TYPE_VECTOR_SUBPARTS (type))); |
| |
| tree_vector_builder elts (type, out_nelts, 1); |
| for (i = 0; i < out_nelts; i++) |
| { |
| tree elt = (i < in_nelts |
| ? VECTOR_CST_ELT (arg1, i) |
| : VECTOR_CST_ELT (arg2, i - in_nelts)); |
| elt = fold_convert_const (code == VEC_PACK_TRUNC_EXPR |
| ? NOP_EXPR |
| : code == VEC_PACK_FLOAT_EXPR |
| ? FLOAT_EXPR : FIX_TRUNC_EXPR, |
| TREE_TYPE (type), elt); |
| if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) |
| return NULL_TREE; |
| elts.quick_push (elt); |
| } |
| |
| return elts.build (); |
| } |
| |
| case VEC_WIDEN_MULT_LO_EXPR: |
| case VEC_WIDEN_MULT_HI_EXPR: |
| case VEC_WIDEN_MULT_EVEN_EXPR: |
| case VEC_WIDEN_MULT_ODD_EXPR: |
| { |
| unsigned HOST_WIDE_INT out_nelts, in_nelts, out, ofs, scale; |
| |
| if (TREE_CODE (arg1) != VECTOR_CST || TREE_CODE (arg2) != VECTOR_CST) |
| return NULL_TREE; |
| |
| if (!VECTOR_CST_NELTS (arg1).is_constant (&in_nelts)) |
| return NULL_TREE; |
| out_nelts = in_nelts / 2; |
| gcc_assert (known_eq (in_nelts, VECTOR_CST_NELTS (arg2)) |
| && known_eq (out_nelts, TYPE_VECTOR_SUBPARTS (type))); |
| |
| if (code == VEC_WIDEN_MULT_LO_EXPR) |
| scale = 0, ofs = BYTES_BIG_ENDIAN ? out_nelts : 0; |
| else if (code == VEC_WIDEN_MULT_HI_EXPR) |
| scale = 0, ofs = BYTES_BIG_ENDIAN ? 0 : out_nelts; |
| else if (code == VEC_WIDEN_MULT_EVEN_EXPR) |
| scale = 1, ofs = 0; |
| else /* if (code == VEC_WIDEN_MULT_ODD_EXPR) */ |
| scale = 1, ofs = 1; |
| |
| tree_vector_builder elts (type, out_nelts, 1); |
| for (out = 0; out < out_nelts; out++) |
| { |
| unsigned int in = (out << scale) + ofs; |
| tree t1 = fold_convert_const (NOP_EXPR, TREE_TYPE (type), |
| VECTOR_CST_ELT (arg1, in)); |
| tree t2 = fold_convert_const (NOP_EXPR, TREE_TYPE (type), |
| VECTOR_CST_ELT (arg2, in)); |
| |
| if (t1 == NULL_TREE || t2 == NULL_TREE) |
| return NULL_TREE; |
| tree elt = const_binop (MULT_EXPR, t1, t2); |
| if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) |
| return NULL_TREE; |
| elts.quick_push (elt); |
| } |
| |
| return elts.build (); |
| } |
| |
| 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); |
| } |
| |
| /* Compute CODE ARG1 with resulting type TYPE with ARG1 being constant. |
| Return zero if computing the constants is not possible. */ |
| |
| tree |
| const_unop (enum tree_code code, tree type, tree arg0) |
| { |
| /* Don't perform the operation, other than NEGATE and ABS, if |
| flag_signaling_nans is on and the operand is a signaling NaN. */ |
| if (TREE_CODE (arg0) == REAL_CST |
| && HONOR_SNANS (arg0) |
| && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg0)) |
| && code != NEGATE_EXPR |
| && code != ABS_EXPR |
| && code != ABSU_EXPR) |
| return NULL_TREE; |
| |
| switch (code) |
| { |
| CASE_CONVERT: |
| case FLOAT_EXPR: |
| case FIX_TRUNC_EXPR: |
| case FIXED_CONVERT_EXPR: |
| return fold_convert_const (code, type, arg0); |
| |
| case ADDR_SPACE_CONVERT_EXPR: |
| /* If the source address is 0, and the source address space |
| cannot have a valid object at 0, fold to dest type null. */ |
| if (integer_zerop (arg0) |
| && !(targetm.addr_space.zero_address_valid |
| (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))))) |
| return fold_convert_const (code, type, arg0); |
| break; |
| |
| case VIEW_CONVERT_EXPR: |
| return fold_view_convert_expr (type, arg0); |
| |
| case NEGATE_EXPR: |
| { |
| /* Can't call fold_negate_const directly here as that doesn't |
| handle all cases and we might not be able to negate some |
| constants. */ |
| tree tem = fold_negate_expr (UNKNOWN_LOCATION, arg0); |
| if (tem && CONSTANT_CLASS_P (tem)) |
| return tem; |
| break; |
| } |
| |
| case ABS_EXPR: |
| case ABSU_EXPR: |
| if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST) |
| return fold_abs_const (arg0, type); |
| break; |
| |
| case CONJ_EXPR: |
| if (TREE_CODE (arg0) == COMPLEX_CST) |
| { |
| tree ipart = fold_negate_const (TREE_IMAGPART (arg0), |
| TREE_TYPE (type)); |
| return build_complex (type, TREE_REALPART (arg0), ipart); |
| } |
| break; |
| |
| case BIT_NOT_EXPR: |
| if (TREE_CODE (arg0) == INTEGER_CST) |
| return fold_not_const (arg0, type); |
| else if (POLY_INT_CST_P (arg0)) |
| return wide_int_to_tree (type, -poly_int_cst_value (arg0)); |
| /* Perform BIT_NOT_EXPR on each element individually. */ |
| else if (TREE_CODE (arg0) == VECTOR_CST) |
| { |
| tree elem; |
| |
| /* This can cope with stepped encodings because ~x == -1 - x. */ |
| tree_vector_builder elements; |
| elements.new_unary_operation (type, arg0, true); |
| unsigned int i, count = elements.encoded_nelts (); |
| for (i = 0; i < count; ++i) |
| { |
| elem = VECTOR_CST_ELT (arg0, i); |
| elem = const_unop (BIT_NOT_EXPR, TREE_TYPE (type), elem); |
| if (elem == NULL_TREE) |
| break; |
| elements.quick_push (elem); |
| } |
| if (i == count) |
| return elements.build (); |
| } |
| break; |
| |
| case TRUTH_NOT_EXPR: |
| if (TREE_CODE (arg0) == INTEGER_CST) |
| return constant_boolean_node (integer_zerop (arg0), type); |
| break; |
| |
| case REALPART_EXPR: |
| if (TREE_CODE (arg0) == COMPLEX_CST) |
| return fold_convert (type, TREE_REALPART (arg0)); |
| break; |
| |
| case IMAGPART_EXPR: |
| if (TREE_CODE (arg0) == COMPLEX_CST) |
| return fold_convert (type, TREE_IMAGPART (arg0)); |
| break; |
| |
| case VEC_UNPACK_LO_EXPR: |
| case VEC_UNPACK_HI_EXPR: |
| case VEC_UNPACK_FLOAT_LO_EXPR: |
| case VEC_UNPACK_FLOAT_HI_EXPR: |
| case VEC_UNPACK_FIX_TRUNC_LO_EXPR: |
| case VEC_UNPACK_FIX_TRUNC_HI_EXPR: |
| { |
| unsigned HOST_WIDE_INT out_nelts, in_nelts, i; |
| enum tree_code subcode; |
| |
| if (TREE_CODE (arg0) != VECTOR_CST) |
| return NULL_TREE; |
| |
| if (!VECTOR_CST_NELTS (arg0).is_constant (&in_nelts)) |
| return NULL_TREE; |
| out_nelts = in_nelts / 2; |
| gcc_assert (known_eq (out_nelts, TYPE_VECTOR_SUBPARTS (type))); |
| |
| unsigned int offset = 0; |
| if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_UNPACK_LO_EXPR |
| || code == VEC_UNPACK_FLOAT_LO_EXPR |
| || code == VEC_UNPACK_FIX_TRUNC_LO_EXPR)) |
| offset = out_nelts; |
| |
| if (code == VEC_UNPACK_LO_EXPR || code == VEC_UNPACK_HI_EXPR) |
| subcode = NOP_EXPR; |
| else if (code == VEC_UNPACK_FLOAT_LO_EXPR |
| || code == VEC_UNPACK_FLOAT_HI_EXPR) |
| subcode = FLOAT_EXPR; |
| else |
| subcode = FIX_TRUNC_EXPR; |
| |
| tree_vector_builder elts (type, out_nelts, 1); |
| for (i = 0; i < out_nelts; i++) |
| { |
| tree elt = fold_convert_const (subcode, TREE_TYPE (type), |
| VECTOR_CST_ELT (arg0, i + offset)); |
| if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) |
| return NULL_TREE; |
| elts.quick_push (elt); |
| } |
| |
| return elts.build (); |
| } |
| |
| case VEC_DUPLICATE_EXPR: |
| if (CONSTANT_CLASS_P (arg0)) |
| return build_vector_from_val (type, arg0); |
| return NULL_TREE; |
| |
| default: |
| break; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* Create a sizetype INT_CST node with NUMBER sign extended. KIND |
| indicates which particular sizetype to create. */ |
| |
| tree |
| size_int_kind (poly_int64 number, enum size_type_kind kind) |
| { |
| return build_int_cst (sizetype_tab[(int) kind], number); |
| } |
| |
| /* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE |
| is a tree code. The type of the result is taken from the operands. |
| Both must be equivalent integer types, ala int_binop_types_match_p. |
| If the operands are constant, so is the result. */ |
| |
| tree |
| size_binop_loc (location_t loc, enum tree_code code, tree arg0, tree arg1) |
| { |
| tree type = TREE_TYPE (arg0); |
| |
| if (arg0 == error_mark_node || arg1 == error_mark_node) |
| return error_mark_node; |
| |
| gcc_assert (int_binop_types_match_p (code, TREE_TYPE (arg0), |
| TREE_TYPE (arg1))); |
| |
| /* Handle the special case of two poly_int constants faster. */ |
| if (poly_int_tree_p (arg0) && poly_int_tree_p (arg1)) |
| { |
| /* And some specific cases even faster than that. */ |
| if (code == PLUS_EXPR) |
| { |
| if (integer_zerop (arg0) |
| && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0))) |
| return arg1; |
| if (integer_zerop (arg1) |
| && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1))) |
| return arg0; |
| } |
| else if (code == MINUS_EXPR) |
| { |
| if (integer_zerop (arg1) |
| && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1))) |
| return arg0; |
| } |
| else if (code == MULT_EXPR) |
| { |
| if (integer_onep (arg0) |
| && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0))) |
| return arg1; |
| } |
| |
| /* Handle general case of two integer constants. For sizetype |
| constant calculations we always want to know about overflow, |
| even in the unsigned case. */ |
| tree res = int_const_binop (code, arg0, arg1, -1); |
| if (res != NULL_TREE) |
| return res; |
| } |
| |
| return fold_build2_loc (loc, code, type, arg0, arg1); |
| } |
| |
| /* Given two values, either both of sizetype or both of bitsizetype, |
| compute the difference between the two values. Return the value |
| in signed type corresponding to the type of the operands. */ |
| |
| tree |
| size_diffop_loc (location_t loc, tree arg0, tree arg1) |
| { |
| tree type = TREE_TYPE (arg0); |
| tree ctype; |
| |
| gcc_assert (int_binop_types_match_p (MINUS_EXPR, TREE_TYPE (arg0), |
| TREE_TYPE (arg1))); |
| |
| /* If the type is already signed, just do the simple thing. */ |
| if (!TYPE_UNSIGNED (type)) |
| return size_binop_loc (loc, MINUS_EXPR, arg0, arg1); |
| |
| if (type == sizetype) |
| ctype = ssizetype; |
| else if (type == bitsizetype) |
| ctype = sbitsizetype; |
| else |
| ctype = signed_type_for (type); |
| |
| /* If either operand is not a constant, do the conversions to the signed |
| type and subtract. The hardware will do the right thing with any |
| overflow in the subtraction. */ |
| if (TREE_CODE (arg0) != INTEGER_CST || TREE_CODE (arg1) != INTEGER_CST) |
| return size_binop_loc (loc, MINUS_EXPR, |
| fold_convert_loc (loc, ctype, arg0), |
| fold_convert_loc (loc, ctype, arg1)); |
| |
| /* If ARG0 is larger than ARG1, subtract and return the result in CTYPE. |
| Otherwise, subtract the other way, convert to CTYPE (we know that can't |
| overflow) and negate (which can't either). Special-case a result |
| of zero while we're here. */ |
| if (tree_int_cst_equal (arg0, arg1)) |
| return build_int_cst (ctype, 0); |
| else if (tree_int_cst_lt (arg1, arg0)) |
| return fold_convert_loc (loc, ctype, |
| size_binop_loc (loc, MINUS_EXPR, arg0, arg1)); |
| else |
| return size_binop_loc (loc, MINUS_EXPR, build_int_cst (ctype, 0), |
| fold_convert_loc (loc, ctype, |
| size_binop_loc (loc, |
| MINUS_EXPR, |
| arg1, arg0))); |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions of an |
| INTEGER_CST to another integer type. */ |
| |
| static tree |
| fold_convert_const_int_from_int (tree type, const_tree arg1) |
| { |
| /* Given an integer constant, make new constant with new type, |
| appropriately sign-extended or truncated. Use widest_int |
| so that any extension is done according ARG1's type. */ |
| return force_fit_type (type, wi::to_widest (arg1), |
| !POINTER_TYPE_P (TREE_TYPE (arg1)), |
| TREE_OVERFLOW (arg1)); |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions a REAL_CST |
| to an integer type. */ |
| |
| static tree |
| fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg1) |
| { |
| bool overflow = false; |
| tree t; |
| |
| /* The following code implements the floating point to integer |
| conversion rules required by the Java Language Specification, |
| that IEEE NaNs are mapped to zero and values that overflow |
| the target precision saturate, i.e. values greater than |
| INT_MAX are mapped to INT_MAX, and values less than INT_MIN |
| are mapped to INT_MIN. These semantics are allowed by the |
| C and C++ standards that simply state that the behavior of |
| FP-to-integer conversion is unspecified upon overflow. */ |
| |
| wide_int val; |
| REAL_VALUE_TYPE r; |
| REAL_VALUE_TYPE x = TREE_REAL_CST (arg1); |
| |
| switch (code) |
| { |
| case FIX_TRUNC_EXPR: |
| real_trunc (&r, VOIDmode, &x); |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* If R is NaN, return zero and show we have an overflow. */ |
| if (REAL_VALUE_ISNAN (r)) |
| { |
| overflow = true; |
| val = wi::zero (TYPE_PRECISION (type)); |
| } |
| |
| /* See if R is less than the lower bound or greater than the |
| upper bound. */ |
| |
| if (! overflow) |
| { |
| tree lt = TYPE_MIN_VALUE (type); |
| REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt); |
| if (real_less (&r, &l)) |
| { |
| overflow = true; |
| val = wi::to_wide (lt); |
| } |
| } |
| |
| if (! overflow) |
| { |
| tree ut = TYPE_MAX_VALUE (type); |
| if (ut) |
| { |
| REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut); |
| if (real_less (&u, &r)) |
| { |
| overflow = true; |
| val = wi::to_wide (ut); |
| } |
| } |
| } |
| |
| if (! overflow) |
| val = real_to_integer (&r, &overflow, TYPE_PRECISION (type)); |
| |
| t = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (arg1)); |
| return t; |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions of a |
| FIXED_CST to an integer type. */ |
| |
| static tree |
| fold_convert_const_int_from_fixed (tree type, const_tree arg1) |
| { |
| tree t; |
| double_int temp, temp_trunc; |
| scalar_mode mode; |
| |
| /* Right shift FIXED_CST to temp by fbit. */ |
| temp = TREE_FIXED_CST (arg1).data; |
| mode = TREE_FIXED_CST (arg1).mode; |
| if (GET_MODE_FBIT (mode) < HOST_BITS_PER_DOUBLE_INT) |
| { |
| temp = temp.rshift (GET_MODE_FBIT (mode), |
| HOST_BITS_PER_DOUBLE_INT, |
| SIGNED_FIXED_POINT_MODE_P (mode)); |
| |
| /* Left shift temp to temp_trunc by fbit. */ |
| temp_trunc = temp.lshift (GET_MODE_FBIT (mode), |
| HOST_BITS_PER_DOUBLE_INT, |
| SIGNED_FIXED_POINT_MODE_P (mode)); |
| } |
| else |
| { |
| temp = double_int_zero; |
| temp_trunc = double_int_zero; |
| } |
| |
| /* If FIXED_CST is negative, we need to round the value toward 0. |
| By checking if the fractional bits are not zero to add 1 to temp. */ |
| if (SIGNED_FIXED_POINT_MODE_P (mode) |
| && temp_trunc.is_negative () |
| && TREE_FIXED_CST (arg1).data != temp_trunc) |
| temp += double_int_one; |
| |
| /* Given a fixed-point constant, make new constant with new type, |
| appropriately sign-extended or truncated. */ |
| t = force_fit_type (type, temp, -1, |
| (temp.is_negative () |
| && (TYPE_UNSIGNED (type) |
| < TYPE_UNSIGNED (TREE_TYPE (arg1)))) |
| | TREE_OVERFLOW (arg1)); |
| |
| return t; |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions a REAL_CST |
| to another floating point type. */ |
| |
| static tree |
| fold_convert_const_real_from_real (tree type, const_tree arg1) |
| { |
| REAL_VALUE_TYPE value; |
| tree t; |
| |
| /* Don't perform the operation if flag_signaling_nans is on |
| and the operand is a signaling NaN. */ |
| if (HONOR_SNANS (arg1) |
| && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg1))) |
| return NULL_TREE; |
| |
| real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1)); |
| t = build_real (type, value); |
| |
| /* If converting an infinity or NAN to a representation that doesn't |
| have one, set the overflow bit so that we can produce some kind of |
| error message at the appropriate point if necessary. It's not the |
| most user-friendly message, but it's better than nothing. */ |
| if (REAL_VALUE_ISINF (TREE_REAL_CST (arg1)) |
| && !MODE_HAS_INFINITIES (TYPE_MODE (type))) |
| TREE_OVERFLOW (t) = 1; |
| else if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)) |
| && !MODE_HAS_NANS (TYPE_MODE (type))) |
| TREE_OVERFLOW (t) = 1; |
| /* Regular overflow, conversion produced an infinity in a mode that |
| can't represent them. */ |
| else if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) |
| && REAL_VALUE_ISINF (value) |
| && !REAL_VALUE_ISINF (TREE_REAL_CST (arg1))) |
| TREE_OVERFLOW (t) = 1; |
| else |
| TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); |
| return t; |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions a FIXED_CST |
| to a floating point type. */ |
| |
| static tree |
| fold_convert_const_real_from_fixed (tree type, const_tree arg1) |
| { |
| REAL_VALUE_TYPE value; |
| tree t; |
| |
| real_convert_from_fixed (&value, SCALAR_FLOAT_TYPE_MODE (type), |
| &TREE_FIXED_CST (arg1)); |
| t = build_real (type, value); |
| |
| TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); |
| return t; |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions a FIXED_CST |
| to another fixed-point type. */ |
| |
| static tree |
| fold_convert_const_fixed_from_fixed (tree type, const_tree arg1) |
| { |
| FIXED_VALUE_TYPE value; |
| tree t; |
| bool overflow_p; |
| |
| overflow_p = fixed_convert (&value, SCALAR_TYPE_MODE (type), |
| &TREE_FIXED_CST (arg1), TYPE_SATURATING (type)); |
| t = build_fixed (type, value); |
| |
| /* Propagate overflow flags. */ |
| if (overflow_p | TREE_OVERFLOW (arg1)) |
| TREE_OVERFLOW (t) = 1; |
| return t; |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions an INTEGER_CST |
| to a fixed-point type. */ |
| |
| static tree |
| fold_convert_const_fixed_from_int (tree type, const_tree arg1) |
| { |
| FIXED_VALUE_TYPE value; |
| tree t; |
| bool overflow_p; |
| double_int di; |
| |
| gcc_assert (TREE_INT_CST_NUNITS (arg1) <= 2); |
| |
| di.low = TREE_INT_CST_ELT (arg1, 0); |
| if (TREE_INT_CST_NUNITS (arg1) == 1) |
| di.high = (HOST_WIDE_INT) di.low < 0 ? HOST_WIDE_INT_M1 : 0; |
| else |
| di.high = TREE_INT_CST_ELT (arg1, 1); |
| |
| overflow_p = fixed_convert_from_int (&value, SCALAR_TYPE_MODE (type), di, |
| TYPE_UNSIGNED (TREE_TYPE (arg1)), |
| TYPE_SATURATING (type)); |
| t = build_fixed (type, value); |
| |
| /* Propagate overflow flags. */ |
| if (overflow_p | TREE_OVERFLOW (arg1)) |
| TREE_OVERFLOW (t) = 1; |
| return t; |
| } |
| |
| /* A subroutine of fold_convert_const handling conversions a REAL_CST |
| to a fixed-point type. */ |
| |
| static tree |
| fold_convert_const_fixed_from_real (tree type, const_tree arg1) |
| { |
| FIXED_VALUE_TYPE value; |
| tree t; |
| bool overflow_p; |
| |
| overflow_p = fixed_convert_from_real (&value, SCALAR_TYPE_MODE (type), |
| &TREE_REAL_CST (arg1), |
| TYPE_SATURATING (type)); |
| t = build_fixed (type, value); |
| |
| /* Propagate overflow flags. */ |
| if (overflow_p | TREE_OVERFLOW (arg1)) |
| TREE_OVERFLOW (t) = 1; |
| return t; |
| } |
| |
| /* Attempt to fold type conversion operation CODE of expression ARG1 to |
| type TYPE. If no simplification can be done return NULL_TREE. */ |
| |
| static tree |
| fold_convert_const (enum tree_code code, tree type, tree arg1) |
| { |
| tree arg_type = TREE_TYPE (arg1); |
| if (arg_type == type) |
| return arg1; |
| |
| /* We can't widen types, since the runtime value could overflow the |
| original type before being extended to the new type. */ |
| if (POLY_INT_CST_P (arg1) |
| && (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)) |
| && TYPE_PRECISION (type) <= TYPE_PRECISION (arg_type)) |
| return build_poly_int_cst (type, |
| poly_wide_int::from (poly_int_cst_value (arg1), |
| TYPE_PRECISION (type), |
| TYPE_SIGN (arg_type))); |
| |
| if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type) |
| || TREE_CODE (type) == OFFSET_TYPE) |
| { |
| if (TREE_CODE (arg1) == INTEGER_CST) |
| return fold_convert_const_int_from_int (type, arg1); |
| else if (TREE_CODE (arg1) == REAL_CST) |
| return fold_convert_const_int_from_real (code, type, arg1); |
| else if (TREE_CODE (arg1) == FIXED_CST) |
| return fold_convert_const_int_from_fixed (type, arg1); |
| } |
| else if (TREE_CODE (type) == REAL_TYPE) |
| { |
| if (TREE_CODE (arg1) == INTEGER_CST) |
| return build_real_from_int_cst (type, arg1); |
| else if (TREE_CODE (arg1) == REAL_CST) |
| return fold_convert_const_real_from_real (type, arg1); |
| else if (TREE_CODE (arg1) == FIXED_CST) |
| return fold_convert_const_real_from_fixed (type, arg1); |
| } |
| else if (TREE_CODE (type) == FIXED_POINT_TYPE) |
| { |
| if (TREE_CODE (arg1) == FIXED_CST) |
| return fold_convert_const_fixed_from_fixed (type, arg1); |
| else if (TREE_CODE (arg1) == INTEGER_CST) |
| return fold_convert_const_fixed_from_int (type, arg1); |
| else if (TREE_CODE (arg1) == REAL_CST) |
| return fold_convert_const_fixed_from_real (type, arg1); |
| } |
| else if (TREE_CODE (type) == VECTOR_TYPE) |
| { |
| if (TREE_CODE (arg1) == VECTOR_CST |
| && known_eq (TYPE_VECTOR_SUBPARTS (type), VECTOR_CST_NELTS (arg1))) |
| { |
| tree elttype = TREE_TYPE (type); |
| tree arg1_elttype = TREE_TYPE (TREE_TYPE (arg1)); |
| /* We can't handle steps directly when extending, since the |
| values need to wrap at the original precision first. */ |
| bool step_ok_p |
| = (INTEGRAL_TYPE_P (elttype) |
| && INTEGRAL_TYPE_P (arg1_elttype) |
| && TYPE_PRECISION (elttype) <= TYPE_PRECISION (arg1_elttype)); |
| tree_vector_builder v; |
| if (!v.new_unary_operation (type, arg1, step_ok_p)) |
| return NULL_TREE; |
| unsigned int len = v.encoded_nelts (); |
| for (unsigned int i = 0; i < len; ++i) |
| { |
| tree elt = VECTOR_CST_ELT (arg1, i); |
| tree cvt = fold_convert_const (code, elttype, elt); |
| if (cvt == NULL_TREE) |
| return NULL_TREE; |
| v.quick_push (cvt); |
| } |
| return v.build (); |
| } |
| } |
| return NULL_TREE; |
| } |
| |
| /* Construct a vector of zero elements of vector type TYPE. */ |
| |
| static tree |
| build_zero_vector (tree type) |
| { |
| tree t; |
| |
| t = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node); |
| return build_vector_from_val (type, t); |
| } |
| |
| /* Returns true, if ARG is convertible to TYPE using a NOP_EXPR. */ |
| |
| bool |
| fold_convertible_p (const_tree type, const_tree arg) |
| { |
| tree orig = TREE_TYPE (arg); |
| |
| if (type == orig) |
| return true; |
| |
| if (TREE_CODE (arg) == ERROR_MARK |
| || TREE_CODE (type) == ERROR_MARK |
| || TREE_CODE (orig) == ERROR_MARK) |
| return false; |
| |
| if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig)) |
| return true; |
| |
| switch (TREE_CODE (type)) |
| { |
| case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: |
| case POINTER_TYPE: case REFERENCE_TYPE: |
| case OFFSET_TYPE: |
| return (INTEGRAL_TYPE_P (orig) |
| || (POINTER_TYPE_P (orig) |
| && TYPE_PRECISION (type) <= TYPE_PRECISION (orig)) |
| || TREE_CODE (orig) == OFFSET_TYPE); |
| |
| case REAL_TYPE: |
| case FIXED_POINT_TYPE: |
| case VOID_TYPE: |
| return TREE_CODE (type) == TREE_CODE (orig); |
| |
| case VECTOR_TYPE: |
| return (VECTOR_TYPE_P (orig) |
| && known_eq (TYPE_VECTOR_SUBPARTS (type), |
| TYPE_VECTOR_SUBPARTS (orig)) |
| && fold_convertible_p (TREE_TYPE (type), TREE_TYPE (orig))); |
| |
| default: |
| return false; |
| } |
| } |
| |
| /* Convert expression ARG to type TYPE. Used by the middle-end for |
| simple conversions in preference to calling the front-end's convert. */ |
| |
| tree |
| fold_convert_loc (location_t loc, tree type, tree arg) |
| { |
| tree orig = TREE_TYPE (arg); |
| tree tem; |
| |
| if (type == orig) |
| return arg; |
| |
| if (TREE_CODE (arg) == ERROR_MARK |
| || TREE_CODE (type) == ERROR_MARK |
| || TREE_CODE (orig) == ERROR_MARK) |
| return error_mark_node; |
| |
| switch (TREE_CODE (type)) |
| { |
| case POINTER_TYPE: |
| case REFERENCE_TYPE: |
| /* Handle conversions between pointers to different address spaces. */ |
| if (POINTER_TYPE_P (orig) |
| && (TYPE_ADDR_SPACE (TREE_TYPE (type)) |
| != TYPE_ADDR_SPACE (TREE_TYPE (orig)))) |
| return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, arg); |
| /* fall through */ |
| |
| case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: |
| case OFFSET_TYPE: |
| if (TREE_CODE (arg) == INTEGER_CST) |
| { |
| tem = fold_convert_const (NOP_EXPR, type, arg); |
| if (tem != NULL_TREE) |
| return tem; |
| } |
| if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig) |
| || TREE_CODE (orig) == OFFSET_TYPE) |
| return fold_build1_loc (loc, NOP_EXPR, type, arg); |
| if (TREE_CODE (orig) == COMPLEX_TYPE) |
| return fold_convert_loc (loc, type, |
| fold_build1_loc (loc, REALPART_EXPR, |
| TREE_TYPE (orig), arg)); |
| gcc_assert (TREE_CODE (orig) == VECTOR_TYPE |
| && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig))); |
| return fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, arg); |
| |
| case REAL_TYPE: |
| if (TREE_CODE (arg) == INTEGER_CST) |
| { |
| tem = fold_convert_const (FLOAT_EXPR, type, arg); |
| if (tem != NULL_TREE) |
| return tem; |
| } |
| else if (TREE_CODE (arg) == REAL_CST) |
| { |
| tem = fold_convert_const (NOP_EXPR, type, arg); |
| if (tem != NULL_TREE) |
| return tem; |
| } |
| else if (TREE_CODE (arg) == FIXED_CST) |
| { |
| tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg); |
| if (tem != NULL_TREE) |
| return tem; |
| } |
| |
| switch (TREE_CODE (orig)) |
| { |
| case INTEGER_TYPE: |
| case BOOLEAN_TYPE: case ENUMERAL_TYPE: |
| case POINTER_TYPE: case REFERENCE_TYPE: |
| return fold_build1_loc (loc, FLOAT_EXPR, type, arg); |
| |
| case REAL_TYPE: |
| return fold_build1_loc (loc, NOP_EXPR, type, arg); |
| |
| case FIXED_POINT_TYPE: |
| return fold_build1_loc (loc, FIXED_CONVERT_EXPR, type, arg); |
| |
| case COMPLEX_TYPE: |
| tem = fold_build1_loc (loc, REALPART_EXPR, TREE_TYPE (orig), arg); |
| return fold_convert_loc (loc, type, tem); |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| case FIXED_POINT_TYPE: |
| if (TREE_CODE (arg) == FIXED_CST || TREE_CODE (arg) == INTEGER_CST |
| || TREE_CODE (arg) == REAL_CST) |
| { |
| tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg); |
| if (tem != NULL_TREE) |
| goto fold_convert_exit; |
| } |
| |
| switch (TREE_CODE (orig)) |
| { |
| case FIXED_POINT_TYPE: |
| case INTEGER_TYPE: |
| case ENUMERAL_TYPE: |
| case BOOLEAN_TYPE: |
| case REAL_TYPE: |
| return fold_build1_loc (loc, FIXED_CONVERT_EXPR, type, arg); |
| |
| case COMPLEX_TYPE: |
| tem = fold_build1_loc (loc, REALPART_EXPR, TREE_TYPE (orig), arg); |
| return fold_convert_loc (loc, type, tem); |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| case COMPLEX_TYPE: |
| switch (TREE_CODE (orig)) |
| { |
| case INTEGER_TYPE: |
| case BOOLEAN_TYPE: case ENUMERAL_TYPE: |
| case POINTER_TYPE: case REFERENCE_TYPE: |
| case REAL_TYPE: |
| case FIXED_POINT_TYPE: |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, |
| fold_convert_loc (loc, TREE_TYPE (type), arg), |
| fold_convert_loc (loc, TREE_TYPE (type), |
| integer_zero_node)); |
| case COMPLEX_TYPE: |
| { |
| tree rpart, ipart; |
| |
| if (TREE_CODE (arg) == COMPLEX_EXPR) |
| { |
| rpart = fold_convert_loc (loc, TREE_TYPE (type), |
| TREE_OPERAND (arg, 0)); |
| ipart = fold_convert_loc (loc, TREE_TYPE (type), |
| TREE_OPERAND (arg, 1)); |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, rpart, ipart); |
| } |
| |
| arg = save_expr (arg); |
| rpart = fold_build1_loc (loc, REALPART_EXPR, TREE_TYPE (orig), arg); |
| ipart = fold_build1_loc (loc, IMAGPART_EXPR, TREE_TYPE (orig), arg); |
| rpart = fold_convert_loc (loc, TREE_TYPE (type), rpart); |
| ipart = fold_convert_loc (loc, TREE_TYPE (type), ipart); |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, rpart, ipart); |
| } |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| case VECTOR_TYPE: |
| if (integer_zerop (arg)) |
| return build_zero_vector (type); |
| gcc_assert (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig))); |
| gcc_assert (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig) |
| || TREE_CODE (orig) == VECTOR_TYPE); |
| return fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, arg); |
| |
| case VOID_TYPE: |
| tem = fold_ignored_result (arg); |
| return fold_build1_loc (loc, NOP_EXPR, type, tem); |
| |
| default: |
| if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig)) |
| return fold_build1_loc (loc, NOP_EXPR, type, arg); |
| gcc_unreachable (); |
| } |
| fold_convert_exit: |
| protected_set_expr_location_unshare (tem, loc); |
| return tem; |
| } |
| |
| /* Return false if expr can be assumed not to be an lvalue, true |
| otherwise. */ |
| |
| static bool |
| maybe_lvalue_p (const_tree x) |
| { |
| /* We only need to wrap lvalue tree codes. */ |
| switch (TREE_CODE (x)) |
| { |
| case VAR_DECL: |
| case PARM_DECL: |
| case RESULT_DECL: |
| case LABEL_DECL: |
| case FUNCTION_DECL: |
| case SSA_NAME: |
| |
| case COMPONENT_REF: |
| case MEM_REF: |
| case INDIRECT_REF: |
| case ARRAY_REF: |
| case ARRAY_RANGE_REF: |
| case BIT_FIELD_REF: |
| case OBJ_TYPE_REF: |
| |
| case REALPART_EXPR: |
| case IMAGPART_EXPR: |
| case PREINCREMENT_EXPR: |
| case PREDECREMENT_EXPR: |
| case SAVE_EXPR: |
| case TRY_CATCH_EXPR: |
| case WITH_CLEANUP_EXPR: |
| case COMPOUND_EXPR: |
| case MODIFY_EXPR: |
| case TARGET_EXPR: |
| case COND_EXPR: |
| case BIND_EXPR: |
| case VIEW_CONVERT_EXPR: |
| break; |
| |
| default: |
| /* Assume the worst for front-end tree codes. */ |
| if ((int)TREE_CODE (x) >= NUM_TREE_CODES) |
| break; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Return an expr equal to X but certainly not valid as an lvalue. */ |
| |
| tree |
| non_lvalue_loc (location_t loc, tree x) |
| { |
| /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to |
| us. */ |
| if (in_gimple_form) |
| return x; |
| |
| if (! maybe_lvalue_p (x)) |
| return x; |
| return build1_loc (loc, NON_LVALUE_EXPR, TREE_TYPE (x), x); |
| } |
| |
| /* Given a tree comparison code, return the code that is the logical inverse. |
| It is generally not safe to do this for floating-point comparisons, except |
| for EQ_EXPR, NE_EXPR, ORDERED_EXPR and UNORDERED_EXPR, so we return |
| ERROR_MARK in this case. */ |
| |
| enum tree_code |
| invert_tree_comparison (enum tree_code code, bool honor_nans) |
| { |
| if (honor_nans && flag_trapping_math && code != EQ_EXPR && code != NE_EXPR |
| && code != ORDERED_EXPR && code != UNORDERED_EXPR) |
| return ERROR_MARK; |
| |
| switch (code) |
| { |
| case EQ_EXPR: |
| return NE_EXPR; |
| case NE_EXPR: |
| return EQ_EXPR; |
| case GT_EXPR: |
| return honor_nans ? UNLE_EXPR : LE_EXPR; |
| case GE_EXPR: |
| return honor_nans ? UNLT_EXPR : LT_EXPR; |
| case LT_EXPR: |
| return honor_nans ? UNGE_EXPR : GE_EXPR; |
| case LE_EXPR: |
| return honor_nans ? UNGT_EXPR : GT_EXPR; |
| case LTGT_EXPR: |
| return UNEQ_EXPR; |
| case UNEQ_EXPR: |
| return LTGT_EXPR; |
| case UNGT_EXPR: |
| return LE_EXPR; |
| case UNGE_EXPR: |
| return LT_EXPR; |
| case UNLT_EXPR: |
| return GE_EXPR; |
| case UNLE_EXPR: |
| return GT_EXPR; |
| case ORDERED_EXPR: |
| return UNORDERED_EXPR; |
| case UNORDERED_EXPR: |
| return ORDERED_EXPR; |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Similar, but return the comparison that results if the operands are |
| swapped. This is safe for floating-point. */ |
| |
| enum tree_code |
| swap_tree_comparison (enum tree_code code) |
| { |
| switch (code) |
| { |
| case EQ_EXPR: |
| case NE_EXPR: |
| case ORDERED_EXPR: |
| case UNORDERED_EXPR: |
| case LTGT_EXPR: |
| case UNEQ_EXPR: |
| return code; |
| case GT_EXPR: |
| return LT_EXPR; |
| case GE_EXPR: |
| return LE_EXPR; |
| case LT_EXPR: |
| return GT_EXPR; |
| case LE_EXPR: |
| return GE_EXPR; |
| case UNGT_EXPR: |
| return UNLT_EXPR; |
| case UNGE_EXPR: |
| return UNLE_EXPR; |
| case UNLT_EXPR: |
| return UNGT_EXPR; |
| case UNLE_EXPR: |
| return UNGE_EXPR; |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| |
| /* Convert a comparison tree code from an enum tree_code representation |
| into a compcode bit-based encoding. This function is the inverse of |
| compcode_to_comparison. */ |
| |
| static enum comparison_code |
| comparison_to_compcode (enum tree_code code) |
| { |
| switch (code) |
| { |
| case LT_EXPR: |
| return COMPCODE_LT; |
| case EQ_EXPR: |
| return COMPCODE_EQ; |
| case LE_EXPR: |
| return COMPCODE_LE; |
| case GT_EXPR: |
| return COMPCODE_GT; |
| case NE_EXPR: |
| return COMPCODE_NE; |
| case GE_EXPR: |
| return COMPCODE_GE; |
| case ORDERED_EXPR: |
| return COMPCODE_ORD; |
| case UNORDERED_EXPR: |
| return COMPCODE_UNORD; |
| case UNLT_EXPR: |
| return COMPCODE_UNLT; |
| case UNEQ_EXPR: |
| return COMPCODE_UNEQ; |
| case UNLE_EXPR: |
| return COMPCODE_UNLE; |
| case UNGT_EXPR: |
| return COMPCODE_UNGT; |
| case LTGT_EXPR: |
| return COMPCODE_LTGT; |
| case UNGE_EXPR: |
| return COMPCODE_UNGE; |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Convert a compcode bit-based encoding of a comparison operator back |
| to GCC's enum tree_code representation. This function is the |
| inverse of comparison_to_compcode. */ |
| |
| static enum tree_code |
| compcode_to_comparison (enum comparison_code code) |
| { |
| switch (code) |
| { |
| case COMPCODE_LT: |
| return LT_EXPR; |
| case COMPCODE_EQ: |
| return EQ_EXPR; |
| case COMPCODE_LE: |
| return LE_EXPR; |
| case COMPCODE_GT: |
| return GT_EXPR; |
| case COMPCODE_NE: |
| return NE_EXPR; |
| case COMPCODE_GE: |
| return GE_EXPR; |
| case COMPCODE_ORD: |
| return ORDERED_EXPR; |
| case COMPCODE_UNORD: |
| return UNORDERED_EXPR; |
| case COMPCODE_UNLT: |
| return UNLT_EXPR; |
| case COMPCODE_UNEQ: |
| return UNEQ_EXPR; |
| case COMPCODE_UNLE: |
| return UNLE_EXPR; |
| case COMPCODE_UNGT: |
| return UNGT_EXPR; |
| case COMPCODE_LTGT: |
| return LTGT_EXPR; |
| case COMPCODE_UNGE: |
| return UNGE_EXPR; |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Return true if COND1 tests the opposite condition of COND2. */ |
| |
| bool |
| inverse_conditions_p (const_tree cond1, const_tree cond2) |
| { |
| return (COMPARISON_CLASS_P (cond1) |
| && COMPARISON_CLASS_P (cond2) |
| && (invert_tree_comparison |
| (TREE_CODE (cond1), |
| HONOR_NANS (TREE_OPERAND (cond1, 0))) == TREE_CODE (cond2)) |
| && operand_equal_p (TREE_OPERAND (cond1, 0), |
| TREE_OPERAND (cond2, 0), 0) |
| && operand_equal_p (TREE_OPERAND (cond1, 1), |
| TREE_OPERAND (cond2, 1), 0)); |
| } |
| |
| /* Return a tree for the comparison which is the combination of |
| doing the AND or OR (depending on CODE) of the two operations LCODE |
| and RCODE on the identical operands LL_ARG and LR_ARG. Take into account |
| the possibility of trapping if the mode has NaNs, and return NULL_TREE |
| if this makes the transformation invalid. */ |
| |
| tree |
| combine_comparisons (location_t loc, |
| enum tree_code code, enum tree_code lcode, |
| enum tree_code rcode, tree truth_type, |
| tree ll_arg, tree lr_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; |
| |
| switch (code) |
| { |
| case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: |
| compcode = lcompcode & rcompcode; |
| break; |
| |
| case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: |
| compcode = lcompcode | rcompcode; |
| break; |
| |
| default: |
| return NULL_TREE; |
| } |
| |
| if (!honor_nans) |
| { |
| /* Eliminate unordered comparisons, as well as LTGT and ORD |
| which are not used unless the mode has NaNs. */ |
| compcode &= ~COMPCODE_UNORD; |
| if (compcode == COMPCODE_LTGT) |
| compcode = COMPCODE_NE; |
| else if (compcode == COMPCODE_ORD) |
| compcode = COMPCODE_TRUE; |
| } |
| else if (flag_trapping_math) |
| { |
| /* Check that the original operation and the optimized ones will trap |
| under the same condition. */ |
| bool ltrap = (lcompcode & COMPCODE_UNORD) == 0 |
| && (lcompcode != COMPCODE_EQ) |
| && (lcompcode != COMPCODE_ORD); |
| bool rtrap = (rcompcode & COMPCODE_UNORD) == 0 |
| && (rcompcode != COMPCODE_EQ) |
| && (rcompcode != COMPCODE_ORD); |
| bool trap = (compcode & COMPCODE_UNORD) == 0 |
| && (compcode != COMPCODE_EQ) |
| && (compcode != COMPCODE_ORD); |
| |
| /* In a short-circuited boolean expression the LHS might be |
| such that the RHS, if evaluated, will never trap. For |
| example, in ORD (x, y) && (x < y), we evaluate the RHS only |
| if neither x nor y is NaN. (This is a mixed blessing: for |
| example, the expression above will never trap, hence |
| optimizing it to x < y would be invalid). */ |
| if ((code == TRUTH_ORIF_EXPR && (lcompcode & COMPCODE_UNORD)) |
| || (code == TRUTH_ANDIF_EXPR && !(lcompcode & COMPCODE_UNORD))) |
| rtrap = false; |
| |
| /* If the comparison was short-circuited, and only the RHS |
| trapped, we may now generate a spurious trap. */ |
| if (rtrap && !ltrap |
| && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) |
| return NULL_TREE; |
| |
| /* If we changed the conditions that cause a trap, we lose. */ |
| if ((ltrap || rtrap) != trap) |
| return NULL_TREE; |
| } |
| |
| if (compcode == COMPCODE_TRUE) |
| return constant_boolean_node (true, truth_type); |
| else if (compcode == COMPCODE_FALSE) |
| return constant_boolean_node (false, truth_type); |
| else |
| { |
| enum tree_code tcode; |
| |
| tcode = compcode_to_comparison ((enum comparison_code) compcode); |
| return fold_build2_loc (loc, tcode, truth_type, ll_arg, lr_arg); |
| } |
| } |
| |
| /* Return nonzero if two operands (typically of the same tree node) |
| are necessarily equal. FLAGS modifies behavior as follows: |
| |
| If OEP_ONLY_CONST is set, only return nonzero for constants. |
| This function tests whether the operands are indistinguishable; |
| it does not test whether they are equal using C's == operation. |
| The distinction is important for IEEE floating point, because |
| (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and |
| (2) two NaNs may be indistinguishable, but NaN!=NaN. |
| |
| If OEP_ONLY_CONST is unset, a VAR_DECL is considered equal to itself |
| even though it may hold multiple values during a function. |
| This is because a GCC tree node guarantees that nothing else is |
| executed between the evaluation of its "operands" (which may often |
| be evaluated in arbitrary order). Hence if the operands themselves |
| don't side-effect, the VAR_DECLs, PARM_DECLs etc... must hold the |
| same value in each operand/subexpression. Hence leaving OEP_ONLY_CONST |
| unset means assuming isochronic (or instantaneous) tree equivalence. |
| Unless comparing arbitrary expression trees, such as from different |
| statements, this flag can usually be left unset. |
| |
| 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. |
| |
| If OEP_ADDRESS_OF is set, we are actually comparing addresses of objects, |
| not values of expressions. |
| |
| If OEP_LEXICOGRAPHIC is set, then also handle expressions with side-effects |
| such as MODIFY_EXPR, RETURN_EXPR, as well as STATEMENT_LISTs. |
| |
| If OEP_BITWISE is set, then require the values to be bitwise identical |
| rather than simply numerically equal. Do not take advantage of things |
| like math-related flags or undefined behavior; only return true for |
| values that are provably bitwise identical in all circumstances. |
| |
| Unless OEP_MATCH_SIDE_EFFECTS is set, the function returns false on |
| any operand with side effect. This is unnecesarily conservative in the |
| case we know that arg0 and arg1 are in disjoint code paths (such as in |
| ?: operator). In addition OEP_MATCH_SIDE_EFFECTS is used when comparing |
| addresses with TREE_CONSTANT flag set so we know that &var == &var |
| even if var is volatile. */ |
| |
| bool |
| operand_compare::operand_equal_p (const_tree arg0, const_tree arg1, |
| unsigned int flags) |
| { |
| bool r; |
| if (verify_hash_value (arg0, arg1, flags, &r)) |
| return r; |
| |
| STRIP_ANY_LOCATION_WRAPPER (arg0); |
| STRIP_ANY_LOCATION_WRAPPER (arg1); |
| |
| /* If either is ERROR_MARK, they aren't equal. */ |
| if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK |
| || TREE_TYPE (arg0) == error_mark_node |
| || TREE_TYPE (arg1) == error_mark_node) |
| return false; |
| |
| /* Similar, if either does not have a type (like a template id), |
| they aren't equal. */ |
| if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1)) |
| return false; |
| |
| /* Bitwise identity makes no sense if the values have different layouts. */ |
| if ((flags & OEP_BITWISE) |
| && !tree_nop_conversion_p (TREE_TYPE (arg0), TREE_TYPE (arg1))) |
| return false; |
| |
| /* 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 false; |
| |
| /* Check equality of integer constants before bailing out due to |
| precision differences. */ |
| if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) |
| { |
| /* Address of INTEGER_CST is not defined; check that we did not forget |
| to drop the OEP_ADDRESS_OF flags. */ |
| gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); |
| return tree_int_cst_equal (arg0, arg1); |
| } |
| |
| 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 false; |
| |
| /* 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 false; |
| |
| 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 |
| a match and compare that variant. */ |
| if (TREE_CODE (arg0) != TREE_CODE (arg1) |
| && COMPARISON_CLASS_P (arg0) |
| && COMPARISON_CLASS_P (arg1)) |
| { |
| enum tree_code swap_code = swap_tree_comparison (TREE_CODE (arg1)); |
| |
| if (TREE_CODE (arg0) == swap_code) |
| return operand_equal_p (TREE_OPERAND (arg0, 0), |
| TREE_OPERAND (arg1, 1), flags) |
| && operand_equal_p (TREE_OPERAND (arg0, 1), |
| TREE_OPERAND (arg1, 0), flags); |
| } |
| |
| if (TREE_CODE (arg0) != TREE_CODE (arg1)) |
| { |
| /* NOP_EXPR and CONVERT_EXPR are considered equal. */ |
| 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 true; |
| 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 true; |
| return false; |
| } |
| else |
| return false; |
| } |
| |
| /* When not checking adddresses, this is needed for conversions and for |
| COMPONENT_REF. Might as well play it safe and always test this. */ |
| if (TREE_CODE (TREE_TYPE (arg0)) == ERROR_MARK |
| || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK |
| || (TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)) |
| && !(flags & OEP_ADDRESS_OF))) |
| return false; |
| |
| /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal. |
| We don't care about side effects in that case because the SAVE_EXPR |
| takes care of that for us. In all other cases, two expressions are |
| equal if they have no side effects. If we have two identical |
| expressions with side effects that should be treated the same due |
| to the only side effects being identical SAVE_EXPR's, that will |
| be detected in the recursive calls below. |
| If we are taking an invariant address of two identical objects |
| they are necessarily equal as well. */ |
| if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST) |
| && (TREE_CODE (arg0) == SAVE_EXPR |
| || (flags & OEP_MATCH_SIDE_EFFECTS) |
| || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1)))) |
| return true; |
| |
| /* Next handle constant cases, those for which we can return 1 even |
| if ONLY_CONST is set. */ |
| if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)) |
| switch (TREE_CODE (arg0)) |
| { |
| case INTEGER_CST: |
| return tree_int_cst_equal (arg0, arg1); |
| |
| case FIXED_CST: |
| return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (arg0), |
| TREE_FIXED_CST (arg1)); |
| |
| case REAL_CST: |
| if (real_identical (&TREE_REAL_CST (arg0), &TREE_REAL_CST (arg1))) |
| return true; |
| |
| if (!(flags & OEP_BITWISE) && !HONOR_SIGNED_ZEROS (arg0)) |
| { |
| /* If we do not distinguish between signed and unsigned zero, |
| consider them equal. */ |
| if (real_zerop (arg0) && real_zerop (arg1)) |
| return true; |
| } |
| return false; |
| |
| case VECTOR_CST: |
| { |
| if (VECTOR_CST_LOG2_NPATTERNS (arg0) |
| != VECTOR_CST_LOG2_NPATTERNS (arg1)) |
| return false; |
| |
| if (VECTOR_CST_NELTS_PER_PATTERN (arg0) |
| != VECTOR_CST_NELTS_PER_PATTERN (arg1)) |
| return false; |
| |
| unsigned int count = vector_cst_encoded_nelts (arg0); |
| for (unsigned int i = 0; i < count; ++i) |
| if (!operand_equal_p (VECTOR_CST_ENCODED_ELT (arg0, i), |
| VECTOR_CST_ENCODED_ELT (arg1, i), flags)) |
| return false; |
| return true; |
| } |
| |
| case COMPLEX_CST: |
| return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1), |
| flags) |
| && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1), |
| flags)); |
| |
| case STRING_CST: |
| return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1) |
| && ! memcmp (TREE_STRING_POINTER (arg0), |
| TREE_STRING_POINTER (arg1), |
| TREE_STRING_LENGTH (arg0))); |
| |
| case ADDR_EXPR: |
| gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); |
| return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), |
| flags | OEP_ADDRESS_OF |
| | OEP_MATCH_SIDE_EFFECTS); |
| case CONSTRUCTOR: |
| /* In GIMPLE empty constructors are allowed in initializers of |
| aggregates. */ |
| return !CONSTRUCTOR_NELTS (arg0) && !CONSTRUCTOR_NELTS (arg1); |
| default: |
| break; |
| } |
| |
| /* Don't handle more cases for OEP_BITWISE, since we can't guarantee that |
| two instances of undefined behavior will give identical results. */ |
| if (flags & (OEP_ONLY_CONST | OEP_BITWISE)) |
| return false; |
| |
| /* Define macros to test an operand from arg0 and arg1 for equality and a |
| variant that allows null and views null as being different from any |
| non-null value. In the latter case, if either is null, the both |
| must be; otherwise, do the normal comparison. */ |
| #define OP_SAME(N) operand_equal_p (TREE_OPERAND (arg0, N), \ |
| TREE_OPERAND (arg1, N), flags) |
| |
| #define OP_SAME_WITH_NULL(N) \ |
| ((!TREE_OPERAND (arg0, N) || !TREE_OPERAND (arg1, N)) \ |
| ? TREE_OPERAND (arg0, N) == TREE_OPERAND (arg1, N) : OP_SAME (N)) |
| |
| switch (TREE_CODE_CLASS (TREE_CODE (arg0))) |
| { |
| case tcc_unary: |
| /* Two conversions are equal only if signedness and modes match. */ |
| switch (TREE_CODE (arg0)) |
| { |
| CASE_CONVERT: |
| case FIX_TRUNC_EXPR: |
| if (TYPE_UNSIGNED (TREE_TYPE (arg0)) |
| != TYPE_UNSIGNED (TREE_TYPE (arg1))) |
| return false; |
| break; |
| default: |
| break; |
| } |
| |
| return OP_SAME (0); |
| |
| |
| case tcc_comparison: |
| case tcc_binary: |
| if (OP_SAME (0) && OP_SAME (1)) |
| return true; |
| |
| /* For commutative ops, allow the other order. */ |
| return (commutative_tree_code (TREE_CODE (arg0)) |
| && operand_equal_p (TREE_OPERAND (arg0, 0), |
| TREE_OPERAND (arg1, 1), flags) |
| && operand_equal_p (TREE_OPERAND (arg0, 1), |
| TREE_OPERAND (arg1, 0), flags)); |
| |
| case tcc_reference: |
| /* If either of the pointer (or reference) expressions we are |
| dereferencing contain a side effect, these cannot be equal, |
| but their addresses can be. */ |
| if ((flags & OEP_MATCH_SIDE_EFFECTS) == 0 |
| && (TREE_SIDE_EFFECTS (arg0) |
| || TREE_SIDE_EFFECTS (arg1))) |
| return false; |
| |
| switch (TREE_CODE (arg0)) |
| { |
| case INDIRECT_REF: |
| if (!(flags & OEP_ADDRESS_OF)) |
| { |
| if (TYPE_ALIGN (TREE_TYPE (arg0)) |
| != TYPE_ALIGN (TREE_TYPE (arg1))) |
| return false; |
| /* Verify that the access types are compatible. */ |
| if (TYPE_MAIN_VARIANT (TREE_TYPE (arg0)) |
| != TYPE_MAIN_VARIANT (TREE_TYPE (arg1))) |
| return false; |
| } |
| flags &= ~OEP_ADDRESS_OF; |
| return OP_SAME (0); |
| |
| case IMAGPART_EXPR: |
| /* Require the same offset. */ |
| if (!operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)), |
| TYPE_SIZE (TREE_TYPE (arg1)), |
| flags & ~OEP_ADDRESS_OF)) |
| return false; |
| |
| /* Fallthru. */ |
| case REALPART_EXPR: |
| case VIEW_CONVERT_EXPR: |
| return OP_SAME (0); |
| |
| case TARGET_MEM_REF: |
| case MEM_REF: |
| if (!(flags & OEP_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 false; |
| /* Verify that access happens in similar types. */ |
| if (!types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))) |
| return false; |
| /* Verify that accesses are TBAA compatible. */ |
| if (!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 false; |
| /* Verify that alignment is compatible. */ |
| if (TYPE_ALIGN (TREE_TYPE (arg0)) |
| != TYPE_ALIGN (TREE_TYPE (arg1))) |
| return false; |
| } |
| flags &= ~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: |
| if (!OP_SAME (0)) |
| return false; |
| flags &= ~OEP_ADDRESS_OF; |
| /* Compare the array index by value if it is constant first as we |
| may have different types but same value here. */ |
| return ((tree_int_cst_equal (TREE_OPERAND (arg0, 1), |
| TREE_OPERAND (arg1, 1)) |
| || OP_SAME (1)) |
| && OP_SAME_WITH_NULL (2) |
| && OP_SAME_WITH_NULL (3) |
| /* Compare low bound and element size as with OEP_ADDRESS_OF |
| we have to account for the offset of the ref. */ |
| && (TREE_TYPE (TREE_OPERAND (arg0, 0)) |
| == TREE_TYPE (TREE_OPERAND (arg1, 0)) |
| || (operand_equal_p (array_ref_low_bound |
| (CONST_CAST_TREE (arg0)), |
| array_ref_low_bound |
| (CONST_CAST_TREE (arg1)), flags) |
| && operand_equal_p (array_ref_element_size |
| (CONST_CAST_TREE (arg0)), |
| array_ref_element_size |
| (CONST_CAST_TREE (arg1)), |
| flags)))); |
| |
| case COMPONENT_REF: |
| /* Handle operand 2 the same as for ARRAY_REF. Operand 0 |
| may be NULL when we're called to compare MEM_EXPRs. */ |
| if (!OP_SAME_WITH_NULL (0)) |
| return false; |
| { |
| bool compare_address = flags & OEP_ADDRESS_OF; |
| |
| /* Most of time we only need to compare FIELD_DECLs for equality. |
| However when determining address look into actual offsets. |
| These may match for unions and unshared record types. */ |
| flags &= ~OEP_ADDRESS_OF; |
| if (!OP_SAME (1)) |
| { |
| if (compare_address |
| && (flags & OEP_ADDRESS_OF_SAME_FIELD) == 0) |
| { |
| if (TREE_OPERAND (arg0, 2) |
| || TREE_OPERAND (arg1, 2)) |
| return OP_SAME_WITH_NULL (2); |
| tree field0 = TREE_OPERAND (arg0, 1); |
| tree field1 = TREE_OPERAND (arg1, 1); |
| |
| if (!operand_equal_p (DECL_FIELD_OFFSET (field0), |
| DECL_FIELD_OFFSET (field1), flags) |
| || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0), |
| DECL_FIELD_BIT_OFFSET (field1), |
| flags)) |
| return false; |
| } |
| else |
| return false; |
| } |
| } |
| return OP_SAME_WITH_NULL (2); |
| |
| case BIT_FIELD_REF: |
| if (!OP_SAME (0)) |
| return false; |
| flags &= ~OEP_ADDRESS_OF; |
| return OP_SAME (1) && OP_SAME (2); |
| |
| default: |
| return false; |
| } |
| |
| case tcc_expression: |
| switch (TREE_CODE (arg0)) |
| { |
| case ADDR_EXPR: |
| /* Be sure we pass right ADDRESS_OF flag. */ |
| gcc_checking_assert (!(flags & OEP_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); |
| |
| case TRUTH_ANDIF_EXPR: |
| case TRUTH_ORIF_EXPR: |
| return OP_SAME (0) && OP_SAME (1); |
| |
| case WIDEN_MULT_PLUS_EXPR: |
| case WIDEN_MULT_MINUS_EXPR: |
| if (!OP_SAME (2)) |
| return false; |
| /* The multiplcation operands are commutative. */ |
| /* FALLTHRU */ |
| |
| case TRUTH_AND_EXPR: |
| case TRUTH_OR_EXPR: |
| case TRUTH_XOR_EXPR: |
| if (OP_SAME (0) && OP_SAME (1)) |
| return true; |
| |
| /* Otherwise take into account this is a commutative operation. */ |
| return (operand_equal_p (TREE_OPERAND (arg0, 0), |
| TREE_OPERAND (arg1, 1), flags) |
| && operand_equal_p (TREE_OPERAND (arg0, 1), |
| TREE_OPERAND (arg1, 0), flags)); |
| |
| case COND_EXPR: |
| if (! OP_SAME (1) || ! OP_SAME_WITH_NULL (2)) |
| return false; |
| flags &= ~OEP_ADDRESS_OF; |
| return OP_SAME (0); |
| |
| case BIT_INSERT_EXPR: |
| /* BIT_INSERT_EXPR has an implict operand as the type precision |
| of op1. Need to check to make sure they are the same. */ |
| if (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST |
| && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST |
| && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 1))) |
| != TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 1)))) |
| return false; |
| /* FALLTHRU */ |
| |
| case VEC_COND_EXPR: |
| case DOT_PROD_EXPR: |
| return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); |
| |
| case MODIFY_EXPR: |
| case INIT_EXPR: |
| case COMPOUND_EXPR: |
| case PREDECREMENT_EXPR: |
| case PREINCREMENT_EXPR: |
| case POSTDECREMENT_EXPR: |
| case POSTINCREMENT_EXPR: |
| if (flags & OEP_LEXICOGRAPHIC) |
| return OP_SAME (0) && OP_SAME (1); |
| return false; |
| |
| case CLEANUP_POINT_EXPR: |
| case EXPR_STMT: |
| case SAVE_EXPR: |
| if (flags & OEP_LEXICOGRAPHIC) |
| return OP_SAME (0); |
| return false; |
| |
| case OBJ_TYPE_REF: |
| /* Virtual table reference. */ |
| if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0), |
| OBJ_TYPE_REF_EXPR (arg1), flags)) |
| return false; |
| flags &= ~OEP_ADDRESS_OF; |
| if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0)) |
| != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1))) |
| return false; |
| if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0), |
| OBJ_TYPE_REF_OBJECT (arg1), flags)) |
| return false; |
| if (virtual_method_call_p (arg0)) |
| { |
| if (!virtual_method_call_p (arg1)) |
| return false; |
| return types_same_for_odr (obj_type_ref_class (arg0), |
| obj_type_ref_class (arg1)); |
| } |
| return false; |
| |
| default: |
| return false; |
| } |
| |
| case tcc_vl_exp: |
| switch (TREE_CODE (arg0)) |
| { |
| case CALL_EXPR: |
| 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 false; |
| 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 false; |
| } |
| 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 false; |
| } |
| |
| /* FIXME: We could skip this test for OEP_MATCH_SIDE_EFFECTS. */ |
| { |
| unsigned int cef = call_expr_flags (arg0); |
| if (flags & OEP_PURE_SAME) |
| cef &= ECF_CONST | ECF_PURE; |
| else |
| cef &= ECF_CONST; |
| if (!cef && !(flags & OEP_LEXICOGRAPHIC)) |
| return false; |
| } |
| |
| /* Now see if all the arguments are the same. */ |
| { |
| const_call_expr_arg_iterator iter0, iter1; |
| const_tree a0, a1; |
| for (a0 = first_const_call_expr_arg (arg0, &iter0), |
| a1 = first_const_call_expr_arg (arg1, &iter1); |
| a0 && a1; |
| a0 = next_const_call_expr_arg (&iter0), |
| a1 = next_const_call_expr_arg (&iter1)) |
| if (! operand_equal_p (a0, a1, flags)) |
| return false; |
| |
| /* If we get here and both argument lists are exhausted |
| then the CALL_EXPRs are equal. */ |
| return ! (a0 || a1); |
| } |
| default: |
| return false; |
| } |
| |
| case tcc_declaration: |
| /* Consider __builtin_sqrt equal to sqrt. */ |
| if (TREE_CODE (arg0) == FUNCTION_DECL) |
| return (fndecl_built_in_p (arg0) && fndecl_built_in_p (arg1) |
| && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1) |
| && (DECL_UNCHECKED_FUNCTION_CODE (arg0) |
| == DECL_UNCHECKED_FUNCTION_CODE (arg1))); |
| |
| if (DECL_P (arg0) |
| && (flags & OEP_DECL_NAME) |
| && (flags & OEP_LEXICOGRAPHIC)) |
| { |
| /* Consider decls with the same name equal. The caller needs |
| to make sure they refer to the same entity (such as a function |
| formal parameter). */ |
| tree a0name = DECL_NAME (arg0); |
| tree a1name = DECL_NAME (arg1); |
| const char *a0ns = a0name ? IDENTIFIER_POINTER (a0name) : NULL; |
| const char *a1ns = a1name ? IDENTIFIER_POINTER (a1name) : NULL; |
| return a0ns && a1ns && strcmp (a0ns, a1ns) == 0; |
| } |
| return false; |
| |
| case tcc_exceptional: |
| if (TREE_CODE (arg0) == CONSTRUCTOR) |
| { |
| if (CONSTRUCTOR_NO_CLEARING (arg0) != CONSTRUCTOR_NO_CLEARING (arg1)) |
| return false; |
| |
| /* 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 false; |
| |
| /* 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 (maybe_ne (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)), |
| TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)))) |
| return false; |
| |
| 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 false; |
| |
| 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 false; |
| } |
| return true; |
| } |
| else if (TREE_CODE (arg0) == STATEMENT_LIST |
| && (flags & OEP_LEXICOGRAPHIC)) |
| { |
| /* Compare the STATEMENT_LISTs. */ |
| tree_stmt_iterator tsi1, tsi2; |
| tree body1 = CONST_CAST_TREE (arg0); |
| tree body2 = CONST_CAST_TREE (arg1); |
| for (tsi1 = tsi_start (body1), tsi2 = tsi_start (body2); ; |
| tsi_next (&tsi1), tsi_next (&tsi2)) |
| { |
| /* The lists don't have the same number of statements. */ |
| if (tsi_end_p (tsi1) ^ tsi_end_p (tsi2)) |
| return false; |
| if (tsi_end_p (tsi1) && tsi_end_p (tsi2)) |
| return true; |
| if (!operand_equal_p (tsi_stmt (tsi1), tsi_stmt (tsi2), |
| flags & (OEP_LEXICOGRAPHIC |
| | OEP_NO_HASH_CHECK))) |
| return false; |
| } |
| } |
| return false; |
| |
| case tcc_statement: |
| switch (TREE_CODE (arg0)) |
| { |
| case RETURN_EXPR: |
| if (flags & OEP_LEXICOGRAPHIC) |
| return OP_SAME_WITH_NULL (0); |
| return false; |
| case DEBUG_BEGIN_STMT: |
| if (flags & OEP_LEXICOGRAPHIC) |
| return true; |
| return false; |
| default: |
| return false; |
| } |
| |
| default: |
| return false; |
| } |
| |
| #undef OP_SAME |
| #undef OP_SAME_WITH_NULL |
| } |
| |
| /* Generate a hash value for an expression. This can be used iteratively |
| by passing a previous result as the HSTATE argument. */ |
| |
| void |
| operand_compare::hash_operand (const_tree t, inchash::hash &hstate, |
| unsigned int flags) |
| { |
| int i; |
| enum tree_code code; |
| enum tree_code_class tclass; |
| |
| if (t == NULL_TREE || t == error_mark_node) |
| { |
| hstate.merge_hash (0); |
| return; |
| } |
| |
| STRIP_ANY_LOCATION_WRAPPER (t); |
| |
| if (!(flags & OEP_ADDRESS_OF)) |
| STRIP_NOPS (t); |
| |
| code = TREE_CODE (t); |
| |
| switch (code) |
| { |
| /* Alas, constants aren't shared, so we can't rely on pointer |
| identity. */ |
| case VOID_CST: |
| hstate.merge_hash (0); |
| return; |
| case INTEGER_CST: |
| gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); |
| for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++) |
| hstate.add_hwi (TREE_INT_CST_ELT (t, i)); |
| return; |
| case REAL_CST: |
| { |
| unsigned int val2; |
| if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t)) |
| val2 = rvc_zero; |
| else |
| val2 = real_hash (TREE_REAL_CST_PTR (t)); |
| hstate.merge_hash (val2); |
| return; |
| } |
| case FIXED_CST: |
| { |
| unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t)); |
| hstate.merge_hash (val2); |
| return; |
| } |
| case STRING_CST: |
| hstate.add ((const void *) TREE_STRING_POINTER (t), |
| TREE_STRING_LENGTH (t)); |
| return; |
| case COMPLEX_CST: |
| hash_operand (TREE_REALPART (t), hstate, flags); |
| hash_operand (TREE_IMAGPART (t), hstate, flags); |
| return; |
| case VECTOR_CST: |
| { |
| hstate.add_int (VECTOR_CST_NPATTERNS (t)); |
| hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t)); |
| unsigned int count = vector_cst_encoded_nelts (t); |
| for (unsigned int i = 0; i < count; ++i) |
| hash_operand (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags); |
| return; |
| } |
| case SSA_NAME: |
| /* We can just compare by pointer. */ |
| hstate.add_hwi (SSA_NAME_VERSION (t)); |
| return; |
| case PLACEHOLDER_EXPR: |
| /* The node itself doesn't matter. */ |
| return; |
| case BLOCK: |
| case OMP_CLAUSE: |
| /* Ignore. */ |
| return; |
| case TREE_LIST: |
| /* A list of expressions, for a CALL_EXPR or as the elements of a |
| VECTOR_CST. */ |
| for (; t; t = TREE_CHAIN (t)) |
| hash_operand (TREE_VALUE (t), hstate, flags); |
| return; |
| case CONSTRUCTOR: |
| { |
| unsigned HOST_WIDE_INT idx; |
| tree field, value; |
| flags &= ~OEP_ADDRESS_OF; |
| hstate.add_int (CONSTRUCTOR_NO_CLEARING (t)); |
| FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value) |
| { |
| /* In GIMPLE the indexes can be either NULL or matching i. */ |
| if (field == NULL_TREE) |
| field = bitsize_int (idx); |
| hash_operand (field, hstate, flags); |
| hash_operand (value, hstate, flags); |
| } |
| return; |
| } |
| case STATEMENT_LIST: |
| { |
| tree_stmt_iterator i; |
| for (i = tsi_start (CONST_CAST_TREE (t)); |
| !tsi_end_p (i); tsi_next (&i)) |
| hash_operand (tsi_stmt (i), hstate, flags); |
| return; |
| } |
| case TREE_VEC: |
| for (i = 0; i < TREE_VEC_LENGTH (t); ++i) |
| hash_operand (TREE_VEC_ELT (t, i), hstate, flags); |
| return; |
| case IDENTIFIER_NODE: |
| hstate.add_object (IDENTIFIER_HASH_VALUE (t)); |
| return; |
| case FUNCTION_DECL: |
| /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form. |
| Otherwise nodes that compare equal according to operand_equal_p might |
| get different hash codes. However, don't do this for machine specific |
| or front end builtins, since the function code is overloaded in those |
| cases. */ |
| if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL |
| && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t))) |
| { |
| t = builtin_decl_explicit (DECL_FUNCTION_CODE (t)); |
| code = TREE_CODE (t); |
| } |
| /* FALL THROUGH */ |
| default: |
| if (POLY_INT_CST_P (t)) |
| { |
| for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i) |
| hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i))); |
| return; |
| } |
| tclass = TREE_CODE_CLASS (code); |
| |
| if (tclass == tcc_declaration) |
| { |
| /* DECL's have a unique ID */ |
| hstate.add_hwi (DECL_UID (t)); |
| } |
| else if (tclass == tcc_comparison && !commutative_tree_code (code)) |
| { |
| /* For comparisons that can be swapped, use the lower |
| tree code. */ |
| enum tree_code ccode = swap_tree_comparison (code); |
| if (code < ccode) |
| ccode = code; |
| hstate.add_object (ccode); |
| hash_operand (TREE_OPERAND (t, ccode != code), hstate, flags); |
| hash_operand (TREE_OPERAND (t, ccode == code), hstate, flags); |
| } |
| else if (CONVERT_EXPR_CODE_P (code)) |
| { |
| /* NOP_EXPR and CONVERT_EXPR are considered equal by |
| operand_equal_p. */ |
| enum tree_code ccode = NOP_EXPR; |
| hstate.add_object (ccode); |
| |
| /* Don't hash the type, that can lead to having nodes which |
| compare equal according to operand_equal_p, but which |
| have different hash codes. Make sure to include signedness |
| in the hash computation. */ |
| hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t))); |
| hash_operand (TREE_OPERAND (t, 0), hstate, flags); |
| } |
| /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl. */ |
| else if (code == MEM_REF |
| && (flags & OEP_ADDRESS_OF) != 0 |
| && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR |
| && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0)) |
| && integer_zerop (TREE_OPERAND (t, 1))) |
| hash_operand (TREE_OPERAND (TREE_OPERAND (t, 0), 0), |
| hstate, flags); |
| /* Don't ICE on FE specific trees, or their arguments etc. |
| during operand_equal_p hash verification. */ |
| else if (!IS_EXPR_CODE_CLASS (tclass)) |
| gcc_assert (flags & OEP_HASH_CHECK); |
| else |
| { |
| unsigned int sflags = flags; |
| |
| hstate.add_object (code); |
| |
| switch (code) |
| { |
| case ADDR_EXPR: |
| gcc_checking_assert (!(flags & OEP_ADDRESS_OF)); |
| flags |= OEP_ADDRESS_OF; |
| sflags = flags; |
| break; |
| |
| case INDIRECT_REF: |
| case MEM_REF: |
| case TARGET_MEM_REF: |
| flags &= ~OEP_ADDRESS_OF; |
| sflags = flags; |
| break; |
| |
| case COMPONENT_REF: |
| if (sflags & OEP_ADDRESS_OF) |
| { |
| hash_operand (TREE_OPERAND (t, 0), hstate, flags); |
| if (TREE_OPERAND (t, 2)) |
| hash_operand (TREE_OPERAND (t, 2), hstate, |
| flags & ~OEP_ADDRESS_OF); |
| else |
| { |
| tree field = TREE_OPERAND (t, 1); |
| hash_operand (DECL_FIELD_OFFSET (field), |
| hstate, flags & ~OEP_ADDRESS_OF); |
| hash_operand (DECL_FIELD_BIT_OFFSET (field), |
| hstate, flags & ~OEP_ADDRESS_OF); |
| } |
| return; |
| } |
| break; |
| case ARRAY_REF: |
| case ARRAY_RANGE_REF: |
| case BIT_FIELD_REF: |
| sflags &= ~OEP_ADDRESS_OF; |
| break; |
| |
| case COND_EXPR: |
| flags &= ~OEP_ADDRESS_OF; |
| break; |
| |
| case WIDEN_MULT_PLUS_EXPR: |
| case WIDEN_MULT_MINUS_EXPR: |
| { |
| /* The multiplication operands are commutative. */ |
| inchash::hash one, two; |
| hash_operand (TREE_OPERAND (t, 0), one, flags); |
| hash_operand (TREE_OPERAND (t, 1), two, flags); |
| hstate.add_commutative (one, two); |
| hash_operand (TREE_OPERAND (t, 2), two, flags); |
| return; |
| } |
| |
| case CALL_EXPR: |
| if (CALL_EXPR_FN (t) == NULL_TREE) |
| hstate.add_int (CALL_EXPR_IFN (t)); |
| break; |
| |
| case TARGET_EXPR: |
| /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT. |
| Usually different TARGET_EXPRs just should use |
| different temporaries in their slots. */ |
| hash_operand (TARGET_EXPR_SLOT (t), hstate, flags); |
| return; |
| |
| case OBJ_TYPE_REF: |
| /* Virtual table reference. */ |
| inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags); |
| flags &= ~OEP_ADDRESS_OF; |
| inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags); |
| inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags); |
| if (!virtual_method_call_p (t)) |
| return; |
| if (tree c = obj_type_ref_class (t)) |
| { |
| c = TYPE_NAME (TYPE_MAIN_VARIANT (c)); |
| /* We compute mangled names only when free_lang_data is run. |
| In that case we can hash precisely. */ |
| if (TREE_CODE (c) == TYPE_DECL |
| && DECL_ASSEMBLER_NAME_SET_P (c)) |
| hstate.add_object |
| (IDENTIFIER_HASH_VALUE |
| (DECL_ASSEMBLER_NAME (c))); |
| } |
| return; |
| default: |
| break; |
| } |
| |
| /* Don't hash the type, that can lead to having nodes which |
| compare equal according to operand_equal_p, but which |
| have different hash codes. */ |
| if (code == NON_LVALUE_EXPR) |
| { |
| /* Make sure to include signness in the hash computation. */ |
| hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t))); |
| hash_operand (TREE_OPERAND (t, 0), hstate, flags); |
| } |
| |
| else if (commutative_tree_code (code)) |
| { |
| /* It's a commutative expression. We want to hash it the same |
| however it appears. We do this by first hashing both operands |
| and then rehashing based on the order of their independent |
| hashes. */ |
| inchash::hash one, two; |
| hash_operand (TREE_OPERAND (t, 0), one, flags); |
| hash_operand (TREE_OPERAND (t, 1), two, flags); |
| hstate.add_commutative (one, two); |
| } |
| else |
| for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i) |
| hash_operand (TREE_OPERAND (t, i), hstate, |
| i == 0 ? flags : sflags); |
| } |
| return; |
| } |
| } |
| |
| bool |
| operand_compare::verify_hash_value (const_tree arg0, const_tree arg1, |
| unsigned int flags, bool *ret) |
| { |
| /* When checking and unless comparing DECL names, verify that if |
| the outermost operand_equal_p call returns non-zero then ARG0 |
| and ARG1 have the same hash value. */ |
| if (flag_checking && !(flags & OEP_NO_HASH_CHECK)) |
| { |
| if (operand_equal_p (arg0, arg1, flags | OEP_NO_HASH_CHECK)) |
| { |
| if (arg0 != arg1 && !(flags & OEP_DECL_NAME)) |
| { |
| inchash::hash hstate0 (0), hstate1 (0); |
| hash_operand (arg0, hstate0, flags | OEP_HASH_CHECK); |
| hash_operand (arg1, hstate1, flags | OEP_HASH_CHECK); |
| hashval_t h0 = hstate0.end (); |
| hashval_t h1 = hstate1.end (); |
| gcc_assert (h0 == h1); |
| } |
| *ret = true; |
| } |
| else |
| *ret = false; |
| |
| return true; |
| } |
| |
| return false; |
| } |
| |
| |
| static operand_compare default_compare_instance; |
| |
| /* Conveinece wrapper around operand_compare class because usually we do |
| not need to play with the valueizer. */ |
| |
| bool |
| operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) |
| { |
| return default_compare_instance.operand_equal_p (arg0, arg1, flags); |
| } |
| |
| namespace inchash |
| { |
| |
| /* Generate a hash value for an expression. This can be used iteratively |
| by passing a previous result as the HSTATE argument. |
| |
| This function is intended to produce the same hash for expressions which |
| would compare equal using operand_equal_p. */ |
| void |
| add_expr (const_tree t, inchash::hash &hstate, unsigned int flags) |
| { |
| default_compare_instance.hash_operand (t, hstate, flags); |
| } |
| |
| } |
| |
| /* Similar to operand_equal_p, but see if ARG0 might be a variant of ARG1 |
| with a different signedness or a narrower precision. */ |
| |
| static bool |
| operand_equal_for_comparison_p (tree arg0, tree arg1) |
| { |
| if (operand_equal_p (arg0, arg1, 0)) |
| return true; |
| |
| if (! INTEGRAL_TYPE_P (TREE_TYPE (arg0)) |
| || ! INTEGRAL_TYPE_P (TREE_TYPE (arg1))) |
| return false; |
| |
| /* Discard any conversions that don't change the modes of ARG0 and ARG1 |
| and see if the inner values are the same. This removes any |
| signedness comparison, which doesn't matter here. */ |
| tree op0 = arg0; |
| tree op1 = arg1; |
| STRIP_NOPS (op0); |
| STRIP_NOPS (op1); |
| if (operand_equal_p (op0, op1, 0)) |
| return true; |
| |
| /* Discard a single widening conversion from ARG1 and see if the inner |
| value is the same as ARG0. */ |
| if (CONVERT_EXPR_P (arg1) |
| && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg1, 0))) |
| && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0))) |
| < TYPE_PRECISION (TREE_TYPE (arg1)) |
| && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) |
| return true; |
| |
| return false; |
| } |
| |
| /* See if ARG is an expression that is either a comparison or is performing |
| arithmetic on comparisons. The comparisons must only be comparing |
| two different values, which will be stored in *CVAL1 and *CVAL2; if |
| they are nonzero it means that some operands have already been found. |
| No variables may be used anywhere else in the expression except in the |
| comparisons. |
| |
| If this is true, return 1. Otherwise, return zero. */ |
| |
| static bool |
| twoval_comparison_p (tree arg, tree *cval1, tree *cval2) |
| { |
| enum tree_code code = TREE_CODE (arg); |
| enum tree_code_class tclass = TREE_CODE_CLASS (code); |
| |
| /* We can handle some of the tcc_expression cases here. */ |
| if (tclass == tcc_expression && code == TRUTH_NOT_EXPR) |
| tclass = tcc_unary; |
| else if (tclass == tcc_expression |
| && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR |
| || code == COMPOUND_EXPR)) |
| tclass = tcc_binary; |
| |
| switch (tclass) |
| { |
| case tcc_unary: |
| return twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2); |
| |
| case tcc_binary: |
| return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2) |
| && twoval_comparison_p (TREE_OPERAND (arg, 1), cval1, cval2)); |
| |
| case tcc_constant: |
| return true; |
| |
| case tcc_expression: |
| if (code == COND_EXPR) |
| return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2) |
| && twoval_comparison_p (TREE_OPERAND (arg, 1), cval1, cval2) |
| && twoval_comparison_p (TREE_OPERAND (arg, 2), cval1, cval2)); |
| return false; |
| |
| case tcc_comparison: |
| /* First see if we can handle the first operand, then the second. For |
| the second operand, we know *CVAL1 can't be zero. It must be that |
| one side of the comparison is each of the values; test for the |
| case where this isn't true by failing if the two operands |
| are the same. */ |
| |
| if (operand_equal_p (TREE_OPERAND (arg, 0), |
| TREE_OPERAND (arg, 1), 0)) |
| return false; |
| |
| if (*cval1 == 0) |
| *cval1 = TREE_OPERAND (arg, 0); |
| else if (operand_equal_p (*cval1, TREE_OPERAND (arg, 0), 0)) |
| ; |
| else if (*cval2 == 0) |
| *cval2 = TREE_OPERAND (arg, 0); |
| else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 0), 0)) |
| ; |
| else |
| return false; |
| |
| if (operand_equal_p (*cval1, TREE_OPERAND (arg, 1), 0)) |
| ; |
| else if (*cval2 == 0) |
| *cval2 = TREE_OPERAND (arg, 1); |
| else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 1), 0)) |
| ; |
| else |
| return false; |
| |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| |
| /* ARG is a tree that is known to contain just arithmetic operations and |
| comparisons. Evaluate the operations in the tree substituting NEW0 for |
| any occurrence of OLD0 as an operand of a comparison and likewise for |
| NEW1 and OLD1. */ |
| |
| static tree |
| eval_subst (location_t loc, tree arg, tree old0, tree new0, |
| tree old1, tree new1) |
| { |
| tree type = TREE_TYPE (arg); |
| enum tree_code code = TREE_CODE (arg); |
| enum tree_code_class tclass = TREE_CODE_CLASS (code); |
| |
| /* We can handle some of the tcc_expression cases here. */ |
| if (tclass == tcc_expression && code == TRUTH_NOT_EXPR) |
| tclass = tcc_unary; |
| else if (tclass == tcc_expression |
| && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) |
| tclass = tcc_binary; |
| |
| switch (tclass) |
| { |
| case tcc_unary: |
| return fold_build1_loc (loc, code, type, |
| eval_subst (loc, TREE_OPERAND (arg, 0), |
| old0, new0, old1, new1)); |
| |
| case tcc_binary: |
| return fold_build2_loc (loc, code, type, |
| eval_subst (loc, TREE_OPERAND (arg, 0), |
| old0, new0, old1, new1), |
| eval_subst (loc, TREE_OPERAND (arg, 1), |
| old0, new0, old1, new1)); |
| |
| case tcc_expression: |
| switch (code) |
| { |
| case SAVE_EXPR: |
| return eval_subst (loc, TREE_OPERAND (arg, 0), old0, new0, |
| old1, new1); |
| |
| case COMPOUND_EXPR: |
| return eval_subst (loc, TREE_OPERAND (arg, 1), old0, new0, |
| old1, new1); |
| |
| case COND_EXPR: |
| return fold_build3_loc (loc, code, type, |
| eval_subst (loc, TREE_OPERAND (arg, 0), |
| old0, new0, old1, new1), |
| eval_subst (loc, TREE_OPERAND (arg, 1), |
| old0, new0, old1, new1), |
| eval_subst (loc, TREE_OPERAND (arg, 2), |
| old0, new0, old1, new1)); |
| default: |
| break; |
| } |
| /* Fall through - ??? */ |
| |
| case tcc_comparison: |
| { |
| tree arg0 = TREE_OPERAND (arg, 0); |
| tree arg1 = TREE_OPERAND (arg, 1); |
| |
| /* We need to check both for exact equality and tree equality. The |
| former will be true if the operand has a side-effect. In that |
| case, we know the operand occurred exactly once. */ |
| |
| if (arg0 == old0 || operand_equal_p (arg0, old0, 0)) |
| arg0 = new0; |
| else if (arg0 == old1 || operand_equal_p (arg0, old1, 0)) |
| arg0 = new1; |
| |
| if (arg1 == old0 || operand_equal_p (arg1, old0, 0)) |
| arg1 = new0; |
| else if (arg1 == old1 || operand_equal_p (arg1, old1, 0)) |
| arg1 = new1; |
| |
| return fold_build2_loc (loc, code, type, arg0, arg1); |
| } |
| |
| default: |
| return arg; |
| } |
| } |
| |
| /* Return a tree for the case when the result of an expression is RESULT |
| converted to TYPE and OMITTED was previously an operand of the expression |
| but is now not needed (e.g., we folded OMITTED * 0). |
| |
| If OMITTED has side effects, we must evaluate it. Otherwise, just do |
| the conversion of RESULT to TYPE. */ |
| |
| tree |
| omit_one_operand_loc (location_t loc, tree type, tree result, tree omitted) |
| { |
| tree t = fold_convert_loc (loc, type, result); |
| |
| /* If the resulting operand is an empty statement, just return the omitted |
| statement casted to void. */ |
| if (IS_EMPTY_STMT (t) && TREE_SIDE_EFFECTS (omitted)) |
| return build1_loc (loc, NOP_EXPR, void_type_node, |
| fold_ignored_result (omitted)); |
| |
| if (TREE_SIDE_EFFECTS (omitted)) |
| return build2_loc (loc, COMPOUND_EXPR, type, |
| fold_ignored_result (omitted), t); |
| |
| return non_lvalue_loc (loc, t); |
| } |
| |
| /* Return a tree for the case when the result of an expression is RESULT |
| converted to TYPE and OMITTED1 and OMITTED2 were previously operands |
| of the expression but are now not needed. |
| |
| If OMITTED1 or OMITTED2 has side effects, they must be evaluated. |
| If both OMITTED1 and OMITTED2 have side effects, OMITTED1 is |
| evaluated before OMITTED2. Otherwise, if neither has side effects, |
| just do the conversion of RESULT to TYPE. */ |
| |
| tree |
| omit_two_operands_loc (location_t loc, tree type, tree result, |
| tree omitted1, tree omitted2) |
| { |
| tree t = fold_convert_loc (loc, type, result); |
| |
| if (TREE_SIDE_EFFECTS (omitted2)) |
| t = build2_loc (loc, COMPOUND_EXPR, type, omitted2, t); |
| if (TREE_SIDE_EFFECTS (omitted1)) |
| t = build2_loc (loc, COMPOUND_EXPR, type, omitted1, t); |
| |
| return TREE_CODE (t) != COMPOUND_EXPR ? non_lvalue_loc (loc, t) : t; |
| } |
| |
| |
| /* Return a simplified tree node for the truth-negation of ARG. This |
| never alters ARG itself. We assume that ARG is an operation that |
| returns a truth value (0 or 1). |
| |
| FIXME: one would think we would fold the result, but it causes |
| problems with the dominator optimizer. */ |
| |
| static tree |
| fold_truth_not_expr (location_t loc, tree arg) |
| { |
| tree type = TREE_TYPE (arg); |
| enum tree_code code = TREE_CODE (arg); |
| location_t loc1, loc2; |
| |
| /* If this is a comparison, we can simply invert it, except for |
| floating-point non-equality comparisons, in which case we just |
| enclose a TRUTH_NOT_EXPR around what we have. */ |
| |
| if (TREE_CODE_CLASS (code) == tcc_comparison) |
| { |
| tree op_type = TREE_TYPE (TREE_OPERAND (arg, 0)); |
| if (FLOAT_TYPE_P (op_type) |
| && flag_trapping_math |
| && code != ORDERED_EXPR && code != UNORDERED_EXPR |
| && code != NE_EXPR && code != EQ_EXPR) |
| return NULL_TREE; |
| |
| code = invert_tree_comparison (code, HONOR_NANS (op_type)); |
| if (code == ERROR_MARK) |
| return NULL_TREE; |
| |
| tree ret = build2_loc (loc, code, type, TREE_OPERAND (arg, 0), |
| TREE_OPERAND (arg, 1)); |
| copy_warning (ret, arg); |
| return ret; |
| } |
| |
| switch (code) |
| { |
| case INTEGER_CST: |
| return constant_boolean_node (integer_zerop (arg), type); |
| |
| case TRUTH_AND_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); |
| loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); |
| return build2_loc (loc, TRUTH_OR_EXPR, type, |
| invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), |
| invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); |
| |
| case TRUTH_OR_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); |
| loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); |
| return build2_loc (loc, TRUTH_AND_EXPR, type, |
| invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), |
| invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); |
| |
| case TRUTH_XOR_EXPR: |
| /* Here we can invert either operand. We invert the first operand |
| unless the second operand is a TRUTH_NOT_EXPR in which case our |
| result is the XOR of the first operand with the inside of the |
| negation of the second operand. */ |
| |
| if (TREE_CODE (TREE_OPERAND (arg, 1)) == TRUTH_NOT_EXPR) |
| return build2_loc (loc, TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0), |
| TREE_OPERAND (TREE_OPERAND (arg, 1), 0)); |
| else |
| return build2_loc (loc, TRUTH_XOR_EXPR, type, |
| invert_truthvalue_loc (loc, TREE_OPERAND (arg, 0)), |
| TREE_OPERAND (arg, 1)); |
| |
| case TRUTH_ANDIF_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); |
| loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); |
| return build2_loc (loc, TRUTH_ORIF_EXPR, type, |
| invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), |
| invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); |
| |
| case TRUTH_ORIF_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); |
| loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); |
| return build2_loc (loc, TRUTH_ANDIF_EXPR, type, |
| invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), |
| invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); |
| |
| case TRUTH_NOT_EXPR: |
| return TREE_OPERAND (arg, 0); |
| |
| case COND_EXPR: |
| { |
| tree arg1 = TREE_OPERAND (arg, 1); |
| tree arg2 = TREE_OPERAND (arg, 2); |
| |
| loc1 = expr_location_or (TREE_OPERAND (arg, 1), loc); |
| loc2 = expr_location_or (TREE_OPERAND (arg, 2), loc); |
| |
| /* A COND_EXPR may have a throw as one operand, which |
| then has void type. Just leave void operands |
| as they are. */ |
| return build3_loc (loc, COND_EXPR, type, TREE_OPERAND (arg, 0), |
| VOID_TYPE_P (TREE_TYPE (arg1)) |
| ? arg1 : invert_truthvalue_loc (loc1, arg1), |
| VOID_TYPE_P (TREE_TYPE (arg2)) |
| ? arg2 : invert_truthvalue_loc (loc2, arg2)); |
| } |
| |
| case COMPOUND_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 1), loc); |
| return build2_loc (loc, COMPOUND_EXPR, type, |
| TREE_OPERAND (arg, 0), |
| invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 1))); |
| |
| case NON_LVALUE_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); |
| return invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)); |
| |
| CASE_CONVERT: |
| if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) |
| return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); |
| |
| /* fall through */ |
| |
| case FLOAT_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); |
| return build1_loc (loc, TREE_CODE (arg), type, |
| invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0))); |
| |
| case BIT_AND_EXPR: |
| if (!integer_onep (TREE_OPERAND (arg, 1))) |
| return NULL_TREE; |
| return build2_loc (loc, EQ_EXPR, type, arg, build_int_cst (type, 0)); |
| |
| case SAVE_EXPR: |
| return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); |
| |
| case CLEANUP_POINT_EXPR: |
| loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); |
| return build1_loc (loc, CLEANUP_POINT_EXPR, type, |
| invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0))); |
| |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| /* Fold the truth-negation of ARG. This never alters ARG itself. We |
| assume that ARG is an operation that returns a truth value (0 or 1 |
| for scalars, 0 or -1 for vectors). Return the folded expression if |
| folding is successful. Otherwise, return NULL_TREE. */ |
| |
| static tree |
| fold_invert_truthvalue (location_t loc, tree arg) |
| { |
| tree type = TREE_TYPE (arg); |
| return fold_unary_loc (loc, VECTOR_TYPE_P (type) |
| ? BIT_NOT_EXPR |
| : TRUTH_NOT_EXPR, |
| type, arg); |
| } |
| |
| /* Return a simplified tree node for the truth-negation of ARG. This |
| never alters ARG itself. We assume that ARG is an operation that |
| returns a truth value (0 or 1 for scalars, 0 or -1 for vectors). */ |
| |
| tree |
| invert_truthvalue_loc (location_t loc, tree arg) |
| { |
| if (TREE_CODE (arg) == ERROR_MARK) |
| return arg; |
| |
| tree type = TREE_TYPE (arg); |
| return fold_build1_loc (loc, VECTOR_TYPE_P (type) |
| ? BIT_NOT_EXPR |
| : TRUTH_NOT_EXPR, |
| type, arg); |
| } |
| |
| /* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER |
| starting at BITPOS. The field is unsigned if UNSIGNEDP is nonzero |
| and uses reverse storage order if REVERSEP is nonzero. ORIG_INNER |
| is the original memory reference used to preserve the alias set of |
| the access. */ |
| |
| static tree |
| make_bit_field_ref (location_t loc, tree inner, tree orig_inner, tree type, |
| HOST_WIDE_INT bitsize, poly_int64 bitpos, |
| int unsignedp, int reversep) |
| { |
| tree result, bftype; |
| |
| /* Attempt not to lose the access path if possible. */ |
| if (TREE_CODE (orig_inner) == COMPONENT_REF) |
| { |
| tree ninner = TREE_OPERAND (orig_inner, 0); |
| machine_mode nmode; |
| poly_int64 nbitsize, nbitpos; |
| tree noffset; |
| int nunsignedp, nreversep, nvolatilep = 0; |
| tree base = get_inner_reference (ninner, &nbitsize, &nbitpos, |
| &noffset, &nmode, &nunsignedp, |
| &nreversep, &nvolatilep); |
| if (base == inner |
| && noffset == NULL_TREE |
| && known_subrange_p (bitpos, bitsize, nbitpos, nbitsize) |
| && !reversep |
| && !nreversep |
| && !nvolatilep) |
| { |
| inner = ninner; |
| bitpos -= nbitpos; |
| } |
| } |
| |
| alias_set_type iset = get_alias_set (orig_inner); |
| if (iset == 0 && get_alias_set (inner) != iset) |
| inner = fold_build2 (MEM_REF, TREE_TYPE (inner), |
| build_fold_addr_expr (inner), |
| build_int_cst (ptr_type_node, 0)); |
| |
| if (known_eq (bitpos, 0) && !reversep) |
| { |
| tree size = TYPE_SIZE (TREE_TYPE (inner)); |
| if ((INTEGRAL_TYPE_P (TREE_TYPE (inner)) |
| || POINTER_TYPE_P (TREE_TYPE (inner))) |
| && tree_fits_shwi_p (size) |
| && tree_to_shwi (size) == bitsize) |
| return fold_convert_loc (loc, type, inner); |
| } |
| |
| bftype = type; |
| if (TYPE_PRECISION (bftype) != bitsize |
| || TYPE_UNSIGNED (bftype) == !unsignedp) |
| bftype = build_nonstandard_integer_type (bitsize, 0); |
| |
| result = build3_loc (loc, BIT_FIELD_REF, bftype, inner, |
| bitsize_int (bitsize), bitsize_int (bitpos)); |
| REF_REVERSE_STORAGE_ORDER (result) = reversep; |
| |
| if (bftype != type) |
| result = fold_convert_loc (loc, type, result); |
| |
| return result; |
| } |
| |
| /* Optimize a bit-field compare. |
| |
| There are two cases: First is a compare against a constant and the |
| second is a comparison of two items where the fields are at the same |
| bit position relative to the start of a chunk (byte, halfword, word) |
| large enough to contain it. In these cases we can avoid the shift |
| implicit in bitfield extractions. |
| |
| For constants, we emit a compare of the shifted constant with the |
| BIT_AND_EXPR of a mask and a byte, halfword, or word of the operand being |
| compared. For two fields at the same position, we do the ANDs with the |
| similar mask and compare the result of the ANDs. |
| |
| CODE is the comparison code, known to be either NE_EXPR or EQ_EXPR. |
| COMPARE_TYPE is the type of the comparison, and LHS and RHS |
| are the left and right operands of the comparison, respectively. |
| |
| If the optimization described above can be done, we return the resulting |
| tree. Otherwise we return zero. */ |
| |
| static tree |
| optimize_bit_field_compare (location_t loc, enum tree_code code, |
| tree compare_type, tree lhs, tree rhs) |
| { |
| poly_int64 plbitpos, plbitsize, rbitpos, rbitsize; |
| HOST_WIDE_INT lbitpos, lbitsize, nbitpos, nbitsize; |
| tree type = TREE_TYPE (lhs); |
| tree unsigned_type; |
| int const_p = TREE_CODE (rhs) == INTEGER_CST; |
| machine_mode lmode, rmode; |
| scalar_int_mode nmode; |
| int lunsignedp, runsignedp; |
| int lreversep, rreversep; |
| int lvolatilep = 0, rvolatilep = 0; |
| tree linner, rinner = NULL_TREE; |
| tree mask; |
| tree offset; |
| |
| /* Get all the information about the extractions being done. If the bit size |
| is the same as the size of the underlying object, we aren't doing an |
| extraction at all and so can do nothing. We also don't want to |
| do anything if the inner expression is a PLACEHOLDER_EXPR since we |
| then will no longer be able to replace it. */ |
| linner = get_inner_reference (lhs, &plbitsize, &plbitpos, &offset, &lmode, |
| &lunsignedp, &lreversep, &lvolatilep); |
| if (linner == lhs |
| || !known_size_p (plbitsize) |
| || !plbitsize.is_constant (&lbitsize) |
| || !plbitpos.is_constant (&lbitpos) |
| || known_eq (lbitsize, GET_MODE_BITSIZE (lmode)) |
| || offset != 0 |
| || TREE_CODE (linner) == PLACEHOLDER_EXPR |
| || lvolatilep) |
| return 0; |
| |
| if (const_p) |
| rreversep = lreversep; |
| else |
| { |
| /* If this is not a constant, we can only do something if bit positions, |
| sizes, signedness and storage order are the same. */ |
| rinner |
| = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset, &rmode, |
| &runsignedp, &rreversep, &rvolatilep); |
| |
| if (rinner == rhs |
| || maybe_ne (lbitpos, rbitpos) |
| || maybe_ne (lbitsize, rbitsize) |
| || lunsignedp != runsignedp |
| || lreversep != rreversep |
| || offset != 0 |
| || TREE_CODE (rinner) == PLACEHOLDER_EXPR |
| || rvolatilep) |
| return 0; |
| } |
| |
| /* Honor the C++ memory model and mimic what RTL expansion does. */ |
| poly_uint64 bitstart = 0; |
| poly_uint64 bitend = 0; |
| if (TREE_CODE (lhs) == COMPONENT_REF) |
| { |
| get_bit_range (&bitstart, &bitend, lhs, &plbitpos, &offset); |
| if (!plbitpos.is_constant (&lbitpos) || offset != NULL_TREE) |
| return 0; |
| } |
| |
| /* See if we can find a mode to refer to this field. We should be able to, |
| but fail if we can't. */ |
| if (!get_best_mode (lbitsize, lbitpos, bitstart, bitend, |
| const_p ? TYPE_ALIGN (TREE_TYPE (linner)) |
| : MIN (TYPE_ALIGN (TREE_TYPE (linner)), |
| TYPE_ALIGN (TREE_TYPE (rinner))), |
| BITS_PER_WORD, false, &nmode)) |
| return 0; |
| |
| /* Set signed and unsigned types of the precision of this mode for the |
| shifts below. */ |
| unsigned_type = lang_hooks.types.type_for_mode (nmode, 1); |
| |
| /* Compute the bit position and size for the new reference and our offset |
| within it. If the new reference is the same size as the original, we |
| won't optimize anything, so return zero. */ |
| nbitsize = GET_MODE_BITSIZE (nmode); |
| nbitpos = lbitpos & ~ (nbitsize - 1); |
| lbitpos -= nbitpos; |
| if (nbitsize == lbitsize) |
| return 0; |
| |
| if (lreversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) |
| lbitpos = nbitsize - lbitsize - lbitpos; |
| |
| /* Make the mask to be used against the extracted field. */ |
| mask = build_int_cst_type (unsigned_type, -1); |
| mask = const_binop (LSHIFT_EXPR, mask, size_int (nbitsize - lbitsize)); |
| mask = const_binop (RSHIFT_EXPR, mask, |
| size_int (nbitsize - lbitsize - lbitpos)); |
| |
| if (! const_p) |
| { |
| if (nbitpos < 0) |
| return 0; |
| |
| /* If not comparing with constant, just rework the comparison |
| and return. */ |
| tree t1 = make_bit_field_ref (loc, linner, lhs, unsigned_type, |
| nbitsize, nbitpos, 1, lreversep); |
| t1 = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, t1, mask); |
| tree t2 = make_bit_field_ref (loc, rinner, rhs, unsigned_type, |
| nbitsize, nbitpos, 1, rreversep); |
| t2 = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, t2, mask); |
| return fold_build2_loc (loc, code, compare_type, t1, t2); |
| } |
| |
| /* Otherwise, we are handling the constant case. See if the constant is too |
| big for the field. Warn and return a tree for 0 (false) if so. We do |
| this not only for its own sake, but to avoid having to test for this |
| error case below. If we didn't, we might generate wrong code. |
| |
| For unsigned fields, the constant shifted right by the field length should |
| be all zero. For signed fields, the high-order bits should agree with |
| the sign bit. */ |
| |
| if (lunsignedp) |
| { |
| if (wi::lrshift (wi::to_wide (rhs), lbitsize) != 0) |
| { |
| warning (0, "comparison is always %d due to width of bit-field", |
| code == NE_EXPR); |
| return constant_boolean_node (code == NE_EXPR, compare_type); |
| } |
| } |
| else |
| { |
| wide_int tem = wi::arshift (wi::to_wide (rhs), lbitsize - 1); |
| if (tem != 0 && tem != -1) |
| { |
| warning (0, "comparison is always %d due to width of bit-field", |
| code == NE_EXPR); |
| return constant_boolean_node (code == NE_EXPR, compare_type); |
| } |
| } |
| |
| if (nbitpos < 0) |
| return 0; |
| |
| /* Single-bit compares should always be against zero. */ |
| if (lbitsize == 1 && ! integer_zerop (rhs)) |
| { |
| code = code == EQ_EXPR ? NE_EXPR : EQ_EXPR; |
| rhs = build_int_cst (type, 0); |
| } |
| |
| /* Make a new bitfield reference, shift the constant over the |
| appropriate number of bits and mask it with the computed mask |
| (in case this was a signed field). If we changed it, make a new one. */ |
| lhs = make_bit_field_ref (loc, linner, lhs, unsigned_type, |
| nbitsize, nbitpos, 1, lreversep); |
| |
| rhs = const_binop (BIT_AND_EXPR, |
| const_binop (LSHIFT_EXPR, |
| fold_convert_loc (loc, unsigned_type, rhs), |
| size_int (lbitpos)), |
| mask); |
| |
| lhs = build2_loc (loc, code, compare_type, |
| build2 (BIT_AND_EXPR, unsigned_type, lhs, mask), rhs); |
| return lhs; |
| } |
| |
| /* Subroutine for fold_truth_andor_1: decode a field reference. |
| |
| If EXP is a comparison reference, we return the innermost reference. |
| |
| *PBITSIZE is set to the number of bits in the reference, *PBITPOS is |
| set to the starting bit number. |
| |
| If the innermost field can be completely contained in a mode-sized |
| unit, *PMODE is set to that mode. Otherwise, it is set to VOIDmode. |
| |
| *PVOLATILEP is set to 1 if the any expression encountered is volatile; |
| otherwise it is not changed. |
| |
| *PUNSIGNEDP is set to the signedness of the field. |
| |
| *PREVERSEP is set to the storage order of the field. |
| |
| *PMASK is set to the mask used. This is either contained in a |
| BIT_AND_EXPR or derived from the width of the field. |
| |
| *PAND_MASK is set to the mask found in a BIT_AND_EXPR, if any. |
| |
| Return 0 if this is not a component reference or is one that we can't |
| do anything with. */ |
| |
| static tree |
| decode_field_reference (location_t loc, tree *exp_, HOST_WIDE_INT *pbitsize, |
| HOST_WIDE_INT *pbitpos, machine_mode *pmode, |
| int *punsignedp, int *preversep, int *pvolatilep, |
| tree *pmask, tree *pand_mask) |
| { |
| tree exp = *exp_; |
| tree outer_type = 0; |
| tree and_mask = 0; |
| tree mask, inner, offset; |
| tree unsigned_type; |
| unsigned int precision; |
| |
| /* All the optimizations using this function assume integer fields. |
| There are problems with FP fields since the type_for_size call |
| below can fail for, e.g., XFmode. */ |
| if (! INTEGRAL_TYPE_P (TREE_TYPE (exp))) |
| return NULL_TREE; |
| |
| /* We are interested in the bare arrangement of bits, so strip everything |
| that doesn't affect the machine mode. However, record the type of the |
| outermost expression if it may matter below. */ |
| if (CONVERT_EXPR_P (exp) |
| || TREE_CODE (exp) == NON_LVALUE_EXPR) |
| outer_type = TREE_TYPE (exp); |
| STRIP_NOPS (exp); |
| |
| if (TREE_CODE (exp) == BIT_AND_EXPR) |
| { |
| and_mask = TREE_OPERAND (exp, 1); |
| exp = TREE_OPERAND (exp, 0); |
| STRIP_NOPS (exp); STRIP_NOPS (and_mask); |
| if (TREE_CODE (and_mask) != INTEGER_CST) |
| return NULL_TREE; |
| } |
| |
| poly_int64 poly_bitsize, poly_bitpos; |
| inner = get_inner_reference (exp, &poly_bitsize, &poly_bitpos, &offset, |
| pmode, punsignedp, preversep, pvolatilep); |
| if ((inner == exp && and_mask == 0) |
| || !poly_bitsize.is_constant (pbitsize) |
| || !poly_bitpos.is_constant (pbitpos) |
| || *pbitsize < 0 |
| || offset != 0 |
| || TREE_CODE (inner) == PLACEHOLDER_EXPR |
| /* Reject out-of-bound accesses (PR79731). */ |
| || (! AGGREGATE_TYPE_P (TREE_TYPE (inner)) |
| && compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)), |
| *pbitpos + *pbitsize) < 0)) |
| return NULL_TREE; |
| |
| unsigned_type = lang_hooks.types.type_for_size (*pbitsize, 1); |
| if (unsigned_type == NULL_TREE) |
| return NULL_TREE; |
| |
| *exp_ = exp; |
| |
| /* If the number of bits in the reference is the same as the bitsize of |
| the outer type, then the outer type gives the signedness. Otherwise |
| (in case of a small bitfield) the signedness is unchanged. */ |
| if (outer_type && *pbitsize == TYPE_PRECISION (outer_type)) |
| *punsignedp = TYPE_UNSIGNED (outer_type); |
| |
| /* Compute the mask to access the bitfield. */ |
| precision = TYPE_PRECISION (unsigned_type); |
| |
| mask = build_int_cst_type (unsigned_type, -1); |
| |
| mask = const_binop (LSHIFT_EXPR, mask, size_int (precision - *pbitsize)); |
| mask = const_binop (RSHIFT_EXPR, mask, size_int (precision - *pbitsize)); |
| |
| /* Merge it with the mask we found in the BIT_AND_EXPR, if any. */ |
| if (and_mask != 0) |
| mask = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, |
| fold_convert_loc (loc, unsigned_type, and_mask), mask); |
| |
| *pmask = mask; |
| *pand_mask = and_mask; |
| return inner; |
| } |
| |
| /* Return nonzero if MASK represents a mask of SIZE ones in the low-order |
| bit positions and MASK is SIGNED. */ |
| |
| static bool |
| all_ones_mask_p (const_tree mask, unsigned int size) |
| { |
| tree type = TREE_TYPE (mask); |
| unsigned int precision = TYPE_PRECISION (type); |
| |
| /* If this function returns true when the type of the mask is |
| UNSIGNED, then there will be errors. In particular see |
| gcc.c-torture/execute/990326-1.c. There does not appear to be |
| any documentation paper trail as to why this is so. But the pre |
| wide-int worked with that restriction and it has been preserved |
| here. */ |
| if (size > precision || TYPE_SIGN (type) == UNSIGNED) |
| return false; |
| |
| return wi::mask (size, false, precision) == wi::to_wide (mask); |
| } |
| |
| /* Subroutine for fold: determine if VAL is the INTEGER_CONST that |
| represents the sign bit of EXP's type. If EXP represents a sign |
| or zero extension, also test VAL against the unextended type. |
| The return value is the (sub)expression whose sign bit is VAL, |
| or NULL_TREE otherwise. */ |
| |
| tree |
| sign_bit_p (tree exp, const_tree val) |
| { |
| int width; |
| tree t; |
| |
| /* Tree EXP must have an integral type. */ |
| t = TREE_TYPE (exp); |
| if (! INTEGRAL_TYPE_P (t)) |
| return NULL_TREE; |
| |
| /* Tree VAL must be an integer constant. */ |
| if (TREE_CODE (val) != INTEGER_CST |
| || TREE_OVERFLOW (val)) |
| return NULL_TREE; |
| |
| width = TYPE_PRECISION (t); |
| if (wi::only_sign_bit_p (wi::to_wide (val), width)) |
| return exp; |
| |
| /* Handle extension from a narrower type. */ |
| if (TREE_CODE (exp) == NOP_EXPR |
| && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))) < width) |
| return sign_bit_p (TREE_OPERAND (exp, 0), val); |
| |
| return NULL_TREE; |
| } |
| |
| /* Subroutine for fold_truth_andor_1: determine if an operand is simple enough |
| to be evaluated unconditionally. */ |
| |
| static bool |
| simple_operand_p (const_tree exp) |
| { |
| /* Strip any conversions that don't change the machine mode. */ |
| STRIP_NOPS (exp); |
| |
| return (CONSTANT_CLASS_P (exp) |
| || TREE_CODE (exp) == SSA_NAME |
| || (DECL_P (exp) |
| && ! TREE_ADDRESSABLE (exp) |
| && ! TREE_THIS_VOLATILE (exp) |
| && ! DECL_NONLOCAL (exp) |
| /* Don't regard global variables as simple. They may be |
| allocated in ways unknown to the compiler (shared memory, |
| #pragma weak, etc). */ |
| && ! TREE_PUBLIC (exp) |
| && ! DECL_EXTERNAL (exp) |
| /* Weakrefs are not safe to be read, since they can be NULL. |
| They are !TREE_PUBLIC && !DECL_EXTERNAL but still |
| have DECL_WEAK flag set. */ |
| && (! VAR_OR_FUNCTION_DECL_P (exp) || ! DECL_WEAK (exp)) |
| /* Loading a static variable is unduly expensive, but global |
| registers aren't expensive. */ |
| && (! TREE_STATIC (exp) || DECL_REGISTER (exp)))); |
| } |
| |
| /* Subroutine for fold_truth_andor: determine if an operand is simple enough |
| to be evaluated unconditionally. |
| I addition to simple_operand_p, we assume that comparisons, conversions, |
| and logic-not operations are simple, if their operands are simple, too. */ |
| |
| static bool |
| simple_operand_p_2 (tree exp) |
| { |
| enum tree_code code; |
| |
| if (TREE_SIDE_EFFECTS (exp) || generic_expr_could_trap_p (exp)) |
| return false; |
| |
| while (CONVERT_EXPR_P (exp)) |
| exp = TREE_OPERAND (exp, 0); |
| |
| code = TREE_CODE (exp); |
| |
| if (TREE_CODE_CLASS (code) == tcc_comparison) |
| return (simple_operand_p (TREE_OPERAND (exp, 0)) |
| && simple_operand_p (TREE_OPERAND (exp, 1))); |
| |
| if (code == TRUTH_NOT_EXPR) |
| return simple_operand_p_2 (TREE_OPERAND (exp, 0)); |
| |
| return simple_operand_p (exp); |
| } |
| |
| |
| /* The following functions are subroutines to fold_range_test and allow it to |
| try to change a logical combination of comparisons into a range test. |
| |
| For example, both |
| X == 2 || X == 3 || X == 4 || X == 5 |
| and |
| X >= 2 && X <= 5 |
| are converted to |
| (unsigned) (X - 2) <= 3 |
| |
| We describe each set of comparisons as being either inside or outside |
| a range, using a variable named like IN_P, and then describe the |
| range with a lower and upper bound. If one of the bounds is omitted, |
| it represents either the highest or lowest value of the type. |
| |
| In the comments below, we represent a range by two numbers in brackets |
| preceded by a "+" to designate being inside that range, or a "-" to |
| designate being outside that range, so the condition can be inverted by |
| flipping the prefix. An omitted bound is represented by a "-". For |
| example, "- [-, 10]" means being outside the range starting at the lowest |
| possible value and ending at 10, in other words, being greater than 10. |
| The range "+ [-, -]" is always true and hence the range "- [-, -]" is |
| always false. |
| |
| We set up things so that the missing bounds are handled in a consistent |
| manner so neither a missing bound nor "true" and "false" need to be |
| handled using a special case. */ |
| |
| /* Return the result of applying CODE to ARG0 and ARG1, but handle the case |
| of ARG0 and/or ARG1 being omitted, meaning an unlimited range. UPPER0_P |
| and UPPER1_P are nonzero if the respective argument is an upper bound |
| and zero for a lower. TYPE, if nonzero, is the type of the result; it |
| must be specified for a comparison. ARG1 will be converted to ARG0's |
| type if both are specified. */ |
| |
| static tree |
| range_binop (enum tree_code code, tree type, tree arg0, int upper0_p, |
| tree arg1, int upper1_p) |
| { |
| tree tem; |
| int result; |
| int sgn0, sgn1; |
| |
| /* If neither arg represents infinity, do the normal operation. |
| Else, if not a comparison, return infinity. Else handle the special |
| comparison rules. Note that most of the cases below won't occur, but |
| are handled for consistency. */ |
| |
| if (arg0 != 0 && arg1 != 0) |
| { |
| tem = fold_build2 (code, type != 0 ? type : TREE_TYPE (arg0), |
| arg0, fold_convert (TREE_TYPE (arg0), arg1)); |
| STRIP_NOPS (tem); |
| return TREE_CODE (tem) == INTEGER_CST ? tem : 0; |
| } |
| |
| if (TREE_CODE_CLASS (code) != tcc_comparison) |
| return 0; |
| |
| /* Set SGN[01] to -1 if ARG[01] is a lower bound, 1 for upper, and 0 |
| for neither. In real maths, we cannot assume open ended ranges are |
| the same. But, this is computer arithmetic, where numbers are finite. |
| We can therefore make the transformation of any unbounded range with |
| the value Z, Z being greater than any representable number. This permits |
| us to treat unbounded ranges as equal. */ |
| sgn0 = arg0 != 0 ? 0 : (upper0_p ? 1 : -1); |
| sgn1 = arg1 != 0 ? 0 : (upper1_p ? 1 : -1); |
| switch (code) |
| { |
| case EQ_EXPR: |
| result = sgn0 == sgn1; |
| break; |
| case NE_EXPR: |
| result = sgn0 != sgn1; |
| break; |
| case LT_EXPR: |
| result = sgn0 < sgn1; |
| break; |
| case LE_EXPR: |
| result = sgn0 <= sgn1; |
| break; |
| case GT_EXPR: |
| result = sgn0 > sgn1; |
| break; |
| case GE_EXPR: |
| result = sgn0 >= sgn1; |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| |
| return constant_boolean_node (result, type); |
| } |
| |
| /* Helper routine for make_range. Perform one step for it, return |
| new expression if the loop should continue or NULL_TREE if it should |
| stop. */ |
| |
| tree |
| make_range_step (location_t loc, enum tree_code code, tree arg0, tree arg1, |
| tree exp_type, tree *p_low, tree *p_high, int *p_in_p, |
| bool *strict_overflow_p) |
| { |
| tree arg0_type = TREE_TYPE (arg0); |
| tree n_low, n_high, low = *p_low, high = *p_high; |
| int in_p = *p_in_p, n_in_p; |
| |
| switch (code) |
| { |
| case TRUTH_NOT_EXPR: |
| /* We can only do something if the range is testing for zero. */ |
| if (low == NULL_TREE || high == NULL_TREE |
| || ! integer_zerop (low) || ! integer_zerop (high)) |
| return NULL_TREE; |
| *p_in_p = ! in_p; |
| return arg0; |
| |
| case EQ_EXPR: case NE_EXPR: |
| case LT_EXPR: case LE_EXPR: case GE_EXPR: case GT_EXPR: |
| /* We can only do something if the range is testing for zero |
| and if the second operand is an integer constant. Note that |
| saying something is "in" the range we make is done by |
| complementing IN_P since it will set in the initial case of |
| being not equal to zero; "out" is leaving it alone. */ |
| if (low == NULL_TREE || high == NULL_TREE |
| || ! integer_zerop (low) || ! integer_zerop (high) |
| || TREE_CODE (arg1) != INTEGER_CST) |
| return NULL_TREE; |
| |
| switch (code) |
| { |
| case NE_EXPR: /* - [c, c] */ |
| low = high = arg1; |
| break; |
| case EQ_EXPR: /* + [c, c] */ |
| in_p = ! in_p, low = high = arg1; |
| break; |
| case GT_EXPR: /* - [-, c] */ |
| low = 0, high = arg1; |
| break; |
| case GE_EXPR: /* + [c, -] */ |
| in_p = ! in_p, low = arg1, high = 0; |
| break; |
| case LT_EXPR: /* - [c, -] */ |
| low = arg1, high = 0; |
| break; |
| case LE_EXPR: /* + [-, c] */ |
| in_p = ! in_p, low = 0, high = arg1; |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* If this is an unsigned comparison, we also know that EXP is |
| greater than or equal to zero. We base the range tests we make |
| on that fact, so we record it here so we can parse existing |
| range tests. We test arg0_type since often the return type |
| of, e.g. EQ_EXPR, is boolean. */ |
| if (TYPE_UNSIGNED (arg0_type) && (low == 0 || high == 0)) |
| { |
| if (! merge_ranges (&n_in_p, &n_low, &n_high, |
| in_p, low, high, 1, |
| build_int_cst (arg0_type, 0), |
| NULL_TREE)) |
| return NULL_TREE; |
| |
| in_p = n_in_p, low = n_low, high = n_high; |
| |
| /* If the high bound is missing, but we have a nonzero low |
| bound, reverse the range so it goes from zero to the low bound |
| minus 1. */ |
| if (high == 0 && low && ! integer_zerop (low)) |
| { |
| in_p = ! in_p; |
| high = range_binop (MINUS_EXPR, NULL_TREE, low, 0, |
| build_int_cst (TREE_TYPE (low), 1), 0); |
| low = build_int_cst (arg0_type, 0); |
| } |
| } |
| |
| *p_low = low; |
| *p_high = high; |
| *p_in_p = in_p; |
| return arg0; |
| |
| case NEGATE_EXPR: |
| /* If flag_wrapv and ARG0_TYPE is signed, make sure |
| low and high are non-NULL, then normalize will DTRT. */ |
| if (!TYPE_UNSIGNED (arg0_type) |
| && !TYPE_OVERFLOW_UNDEFINED (arg0_type)) |
| { |
| if (low == NULL_TREE) |
| low = TYPE_MIN_VALUE (arg0_type); |
| if (high == NULL_TREE) |
| high = TYPE_MAX_VALUE (arg0_type); |
| } |
| |
| /* (-x) IN [a,b] -> x in [-b, -a] */ |
| n_low = range_binop (MINUS_EXPR, exp_type, |
| build_int_cst (exp_type, 0), |
| 0, high, 1); |
| n_high = range_binop (MINUS_EXPR, exp_type, |
| build_int_cst (exp_type, 0), |
| 0, low, 0); |
| if (n_high != 0 && TREE_OVERFLOW (n_high)) |
| return NULL_TREE; |
| goto normalize; |
| |
| case BIT_NOT_EXPR: |
| /* ~ X -> -X - 1 */ |
| return build2_loc (loc, MINUS_EXPR, exp_type, negate_expr (arg0), |
| build_int_cst (exp_type, 1)); |
| |
| case PLUS_EXPR: |
| case MINUS_EXPR: |
| if (TREE_CODE (arg1) != INTEGER_CST) |
| return NULL_TREE; |
| |
| /* If flag_wrapv and ARG0_TYPE is signed, then we cannot |
| move a constant to the other side. */ |
| if (!TYPE_UNSIGNED (arg0_type) |
| && !TYPE_OVERFLOW_UNDEFINED (arg0_type)) |
| return NULL_TREE; |
| |
| /* If EXP is signed, any overflow in the computation is undefined, |
| so we don't worry about it so long as our computations on |
| the bounds don't overflow. For unsigned, overflow is defined |
| and this is exactly the right thing. */ |
| n_low = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR, |
| arg0_type, low, 0, arg1, 0); |
| n_high = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR, |
| arg0_type, high, 1, arg1, 0); |
| if ((n_low != 0 && TREE_OVERFLOW (n_low)) |
| || (n_high != 0 && TREE_OVERFLOW (n_high))) |
| return NULL_TREE; |
| |
| if (TYPE_OVERFLOW_UNDEFINED (arg0_type)) |
| *strict_overflow_p = true; |
| |
| normalize: |
| /* Check for an unsigned range which has wrapped around the maximum |
| value thus making n_high < n_low, and normalize it. */ |
| if (n_low && n_high && tree_int_cst_lt (n_high, n_low)) |
| { |
| low = range_binop (PLUS_EXPR, arg0_type, n_high, 0, |
| build_int_cst (TREE_TYPE (n_high), 1), 0); |
| high = range_binop (MINUS_EXPR, arg0_type, n_low, 0, |
| build_int_cst (TREE_TYPE (n_low), 1), 0); |
| |
| /* If the range is of the form +/- [ x+1, x ], we won't |
| be able to normalize it. But then, it represents the |
| whole range or the empty set, so make it |
| +/- [ -, - ]. */ |
| if (tree_int_cst_equal (n_low, low) |
| && tree_int_cst_equal (n_high, high)) |
| low = high = 0; |
| else |
| in_p = ! in_p; |
| } |
| else |
| low = n_low, high = n_high; |
| |
| *p_low = low; |
| *p_high = high; |
| *p_in_p = in_p; |
| return arg0; |
| |
| CASE_CONVERT: |
| case NON_LVALUE_EXPR: |
| if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type)) |
| return NULL_TREE; |
| |
| if (! INTEGRAL_TYPE_P (arg0_type) |
| || (low != 0 && ! int_fits_type_p (low, arg0_type)) |
| || (high != 0 && ! int_fits_type_p (high, arg0_type))) |
| return NULL_TREE; |
| |
| n_low = low, n_high = high; |
| |
| if (n_low != 0) |
| n_low = fold_convert_loc (loc, arg0_type, n_low); |
| |
| if (n_high != 0) |
| n_high = fold_convert_loc (loc, arg0_type, n_high); |
| |
| /* If we're converting arg0 from an unsigned type, to exp, |
| a signed type, we will be doing the comparison as unsigned. |
| The tests above have already verified that LOW and HIGH |
| are both positive. |
| |
| So we have to ensure that we will handle large unsigned |
| values the same way that the current signed bounds treat |
| negative values. */ |
| |
| if (!TYPE_UNSIGNED (exp_type) && TYPE_UNSIGNED (arg0_type)) |
| { |
| tree high_positive; |
| tree equiv_type; |
| /* For fixed-point modes, we need to pass the saturating flag |
| as the 2nd parameter. */ |
| if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (arg0_type))) |
| equiv_type |
| = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type), |
| TYPE_SATURATING (arg0_type)); |
| else |
| equiv_type |
| = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type), 1); |
| |
| /* A range without an upper bound is, naturally, unbounded. |
| Since convert would have cropped a very large value, use |
| the max value for the destination type. */ |
| high_positive |
| = TYPE_MAX_VALUE (equiv_type) ? TYPE_MAX_VALUE (equiv_type) |
| : TYPE_MAX_VALUE (arg0_type); |
| |
| if (TYPE_PRECISION (exp_type) == TYPE_PRECISION (arg0_type)) |
| high_positive = fold_build2_loc (loc, RSHIFT_EXPR, arg0_type, |
| fold_convert_loc (loc, arg0_type, |
| high_positive), |
| build_int_cst (arg0_type, 1)); |
| |
| /* If the low bound is specified, "and" the range with the |
| range for which the original unsigned value will be |
| positive. */ |
| if (low != 0) |
| { |
| if (! merge_ranges (&n_in_p, &n_low, &n_high, 1, n_low, n_high, |
| 1, fold_convert_loc (loc, arg0_type, |
| integer_zero_node), |
| high_positive)) |
| return NULL_TREE; |
| |
| in_p = (n_in_p == in_p); |
| } |
| else |
| { |
| /* Otherwise, "or" the range with the range of the input |
| that will be interpreted as negative. */ |
| if (! merge_ranges (&n_in_p, &n_low, &n_high, 0, n_low, n_high, |
| 1, fold_convert_loc (loc, arg0_type, |
| integer_zero_node), |
| high_positive)) |
| return NULL_TREE; |
| |
| in_p = (in_p != n_in_p); |
| } |
| } |
| |
| *p_low = n_low; |
| *p_high = n_high; |
| *p_in_p = in_p; |
| return arg0; |
| |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| /* Given EXP, a logical expression, set the range it is testing into |
| variables denoted by PIN_P, PLOW, and PHIGH. Return the expression |
| actually being tested. *PLOW and *PHIGH will be made of the same |
| type as the returned expression. If EXP is not a comparison, we |
| will most likely not be returning a useful value and range. Set |
| *STRICT_OVERFLOW_P to true if the return value is only valid |
| because signed overflow is undefined; otherwise, do not change |
| *STRICT_OVERFLOW_P. */ |
| |
| tree |
| make_range (tree exp, int *pin_p, tree *plow, tree *phigh, |
| bool *strict_overflow_p) |
| { |
| enum tree_code code; |
| tree arg0, arg1 = NULL_TREE; |
| tree exp_type, nexp; |
| int in_p; |
| tree low, high; |
| location_t loc = EXPR_LOCATION (exp); |
| |
| /* Start with simply saying "EXP != 0" and then look at the code of EXP |
| and see if we can refine the range. Some of the cases below may not |
| happen, but it doesn't seem worth worrying about this. We "continue" |
| the outer loop when we've changed something; otherwise we "break" |
| the switch, which will "break" the while. */ |
| |
| in_p = 0; |
| low = high = build_int_cst (TREE_TYPE (exp), 0); |
| |
| while (1) |
| { |
| code = TREE_CODE (exp); |
| exp_type = TREE_TYPE (exp); |
| arg0 = NULL_TREE; |
| |
| if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) |
| { |
| if (TREE_OPERAND_LENGTH (exp) > 0) |
| arg0 = TREE_OPERAND (exp, 0); |
| if (TREE_CODE_CLASS (code) == tcc_binary |
| || TREE_CODE_CLASS (code) == tcc_comparison |
| || (TREE_CODE_CLASS (code) == tcc_expression |
| && TREE_OPERAND_LENGTH (exp) > 1)) |
| arg1 = TREE_OPERAND (exp, 1); |
| } |
| if (arg0 == NULL_TREE) |
| break; |
| |
| nexp = make_range_step (loc, code, arg0, arg1, exp_type, &low, |
| &high, &in_p, strict_overflow_p); |
| if (nexp == NULL_TREE) |
| break; |
| exp = nexp; |
| } |
| |
| /* If EXP is a constant, we can evaluate whether this is true or false. */ |
| if (TREE_CODE (exp) == INTEGER_CST) |
| { |
| in_p = in_p == (integer_onep (range_binop (GE_EXPR, integer_type_node, |
| exp, 0, low, 0)) |
| && integer_onep (range_binop (LE_EXPR, integer_type_node, |
| exp, 1, high, 1))); |
| low = high = 0; |
| exp = 0; |
| } |
| |
| *pin_p = in_p, *plow = low, *phigh = high; |
| return exp; |
| } |
| |
| /* Returns TRUE if [LOW, HIGH] range check can be optimized to |
| a bitwise check i.e. when |
| LOW == 0xXX...X00...0 |
| HIGH == 0xXX...X11...1 |
| Return corresponding mask in MASK and stem in VALUE. */ |
| |
| static bool |
| maskable_range_p (const_tree low, const_tree high, tree type, tree *mask, |
| tree *value) |
| { |
| if (TREE_CODE (low) != INTEGER_CST |
| || TREE_CODE (high) != INTEGER_CST) |
| return false; |
| |
| unsigned prec = TYPE_PRECISION (type); |
| wide_int lo = wi::to_wide (low, prec); |
| wide_int hi = wi::to_wide (high, prec); |
| |
| wide_int end_mask = lo ^ hi; |
| if ((end_mask & (end_mask + 1)) != 0 |
| || (lo & end_mask) != 0) |
| return false; |
| |
| wide_int stem_mask = ~end_mask; |
| wide_int stem = lo & stem_mask; |
| if (stem != (hi & stem_mask)) |
| return false; |
| |
| *mask = wide_int_to_tree (type, stem_mask); |
| *value = wide_int_to_tree (type, stem); |
| |
| return true; |
| } |
| |
| /* Helper routine for build_range_check and match.pd. Return the type to |
| perform the check or NULL if it shouldn't be optimized. */ |
| |
| tree |
| range_check_type (tree etype) |
| { |
| /* First make sure that arithmetics in this type is valid, then make sure |
| that it wraps around. */ |
| if (TREE_CODE (etype) == ENUMERAL_TYPE || TREE_CODE (etype) == BOOLEAN_TYPE) |
| etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype), 1); |
| |
| if (TREE_CODE (etype) == INTEGER_TYPE && !TYPE_UNSIGNED (etype)) |
| { |
| tree utype, minv, maxv; |
| |
| /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN |
| for the type in question, as we rely on this here. */ |
| utype = unsigned_type_for (etype); |
| maxv = fold_convert (utype, TYPE_MAX_VALUE (etype)); |
| maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1, |
| build_int_cst (TREE_TYPE (maxv), 1), 1); |
| minv = fold_convert (utype, TYPE_MIN_VALUE (etype)); |
| |
| if (integer_zerop (range_binop (NE_EXPR, integer_type_node, |
| minv, 1, maxv, 1))) |
| etype = utype; |
| else |
| return NULL_TREE; |
| } |
| else if (POINTER_TYPE_P (etype) || TREE_CODE (etype) == OFFSET_TYPE) |
| etype = unsigned_type_for (etype); |
| return etype; |
| } |
| |
| /* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result |
| type, TYPE, return an expression to test if EXP is in (or out of, depending |
| on IN_P) the range. Return 0 if the test couldn't be created. */ |
| |
| tree |
| build_range_check (location_t loc, tree type, tree exp, int in_p, |
| tree low, tree high) |
| { |
| tree etype = TREE_TYPE (exp), mask, value; |
| |
| /* Disable this optimization for function pointer expressions |
| on targets that require function pointer canonicalization. */ |
| if (targetm.have_canonicalize_funcptr_for_compare () |
| && POINTER_TYPE_P (etype) |
| && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (etype))) |
| return NULL_TREE; |
| |
| if (! in_p) |
| { |
| value = build_range_check (loc, type, exp, 1, low, high); |
| if (value != 0) |
| return invert_truthvalue_loc (loc, value); |
| |
| return 0; |
| } |
| |
| if (low == 0 && high == 0) |
| return omit_one_operand_loc (loc, type, build_int_cst (type, 1), exp); |
| |
| if (low == 0) |
| return fold_build2_loc (loc, LE_EXPR, type, exp, |
| fold_convert_loc (loc, etype, high)); |
| |
| if (high == 0) |
| return fold_build2_loc (loc, GE_EXPR, type, exp, |
| fold_convert_loc (loc, etype, low)); |
| |
| if (operand_equal_p (low, high, 0)) |
| return fold_build2_loc (loc, EQ_EXPR, type, exp, |
| fold_convert_loc (loc, etype, low)); |
| |
| if (TREE_CODE (exp) == BIT_AND_EXPR |
| && maskable_range_p (low, high, etype, &mask, &value)) |
| return fold_build2_loc (loc, EQ_EXPR, type, |
| fold_build2_loc (loc, BIT_AND_EXPR, etype, |
| exp, mask), |
| value); |
| |
| if (integer_zerop (low)) |
| { |
| if (! TYPE_UNSIGNED (etype)) |
| { |
| etype = unsigned_type_for (etype); |
| high = fold_convert_loc (loc, etype, high); |
| exp = fold_convert_loc (loc, etype, exp); |
| } |
| return build_range_check (loc, type, exp, 1, 0, high); |
| } |
| |
| /* Optimize (c>=1) && (c<=127) into (signed char)c > 0. */ |
| if (integer_onep (low) && TREE_CODE (high) == INTEGER_CST) |
| { |
| int prec = TYPE_PRECISION (etype); |
| |
| if (wi::mask <widest_int> (prec - 1, false) == wi::to_widest (high)) |
| { |
| if (TYPE_UNSIGNED (etype)) |
| { |
| tree signed_etype = signed_type_for (etype); |
| if (TYPE_PRECISION (signed_etype) != TYPE_PRECISION (etype)) |
| etype |
| = build_nonstandard_integer_type (TYPE_PRECISION (etype), 0); |
| else |
| etype = signed_etype; |
| exp = fold_convert_loc (loc, etype, exp); |
| } |
| return fold_build2_loc (loc, GT_EXPR, type, exp, |
| build_int_cst (etype, 0)); |
| } |
| } |
| |
| /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low). |
| This requires wrap-around arithmetics for the type of the expression. */ |
| etype = range_check_type (etype); |
| if (etype == NULL_TREE) |
| return NULL_TREE; |
| |
| high = fold_convert_loc (loc, etype, high); |
| low = fold_convert_loc (loc, etype, low); |
| exp = fold_convert_loc (loc, etype, exp); |
| |
| value = const_binop (MINUS_EXPR, high, low); |
| |
| if (value != 0 && !TREE_OVERFLOW (value)) |
| return build_range_check (loc, type, |
| fold_build2_loc (loc, MINUS_EXPR, etype, exp, low), |
| 1, build_int_cst (etype, 0), value); |
| |
| return 0; |
| } |
| |
| /* Return the predecessor of VAL in its type, handling the infinite case. */ |
| |
| static tree |
| range_predecessor (tree val) |
| { |
| tree type = TREE_TYPE (val); |
| |
| if (INTEGRAL_TYPE_P (type) |
| && operand_equal_p (val, TYPE_MIN_VALUE (type), 0)) |
| return 0; |
| else |
| return range_binop (MINUS_EXPR, NULL_TREE, val, 0, |
| build_int_cst (TREE_TYPE (val), 1), 0); |
| } |
| |
| /* Return the successor of VAL in its type, handling the infinite case. */ |
| |
| static tree |
| range_successor (tree val) |
| { |
| tree type = TREE_TYPE (val); |
| |
| if (INTEGRAL_TYPE_P (type) |
| && operand_equal_p (val, TYPE_MAX_VALUE (type), 0)) |
| return 0; |
| else |
| return range_binop (PLUS_EXPR, NULL_TREE, val, 0, |
| build_int_cst (TREE_TYPE (val), 1), 0); |
| } |
| |
| /* Given two ranges, see if we can merge them into one. Return 1 if we |
| can, 0 if we can't. Set the output range into the specified parameters. */ |
| |
| bool |
| merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, |
| tree high0, int in1_p, tree low1, tree high1) |
| { |
| int no_overlap; |
| int subset; |
| int temp; |
| tree tem; |
| int in_p; |
| tree low, high; |
| int lowequal = ((low0 == 0 && low1 == 0) |
| || integer_onep (range_binop (EQ_EXPR, integer_type_node, |
| low0, 0, low1, 0))); |
| int highequal = ((high0 == 0 && high1 == 0) |
| || integer_onep (range_binop (EQ_EXPR, integer_type_node, |
| high0, 1, high1, 1))); |
| |
| /* Make range 0 be the range that starts first, or ends last if they |
| start at the same value. Swap them if it isn't. */ |
| if (integer_onep (range_binop (GT_EXPR, integer_type_node, |
| low0, 0, low1, 0)) |
| || (lowequal |
| && integer_onep (range_binop (GT_EXPR, integer_type_node, |
| high1, 1, high0, 1)))) |
| { |
| temp = in0_p, in0_p = in1_p, in1_p = temp; |
| tem = low0, low0 = low1, low1 = tem; |
| tem = high0, high0 = high1, high1 = tem; |
| } |
| |
| /* If the second range is != high1 where high1 is the type maximum of |
| the type, try first merging with < high1 range. */ |
| if (low1 |
| && high1 |
| && TREE_CODE (low1) == INTEGER_CST |
| && (TREE_CODE (TREE_TYPE (low1)) == INTEGER_TYPE |
| || (TREE_CODE (TREE_TYPE (low1)) == ENUMERAL_TYPE |
| && known_eq (TYPE_PRECISION (TREE_TYPE (low1)), |
| GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (low1)))))) |
| && operand_equal_p (low1, high1, 0)) |
| { |
| if (tree_int_cst_equal (low1, TYPE_MAX_VALUE (TREE_TYPE (low1))) |
| && merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, |
| !in1_p, NULL_TREE, range_predecessor (low1))) |
| return true; |
| /* Similarly for the second range != low1 where low1 is the type minimum |
| of the type, try first merging with > low1 range. */ |
| if (tree_int_cst_equal (low1, TYPE_MIN_VALUE (TREE_TYPE (low1))) |
| && merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, |
| !in1_p, range_successor (low1), NULL_TREE)) |
| return true; |
| } |
| |
| /* Now flag two cases, whether the ranges are disjoint or whether the |
| second range is totally subsumed in the first. Note that the tests |
| below are simplified by the ones above. */ |
| no_overlap = integer_onep (range_binop (LT_EXPR, integer_type_node, |
| high0, 1, low1, 0)); |
| subset = integer_onep (range_binop (LE_EXPR, integer_type_node, |
| high1, 1, high0, 1)); |
| |
| /* We now have four cases, depending on whether we are including or |
| excluding the two ranges. */ |
| if (in0_p && in1_p) |
| { |
| /* If they don't overlap, the result is false. If the second range |
| is a subset it is the result. Otherwise, the range is from the start |
| of the second to the end of the first. */ |
| if (no_overlap) |
| in_p = 0, low = high = 0; |
| else if (subset) |
| in_p = 1, low = low1, high = high1; |
| else |
| in_p = 1, low = low1, high = high0; |
| } |
| |
| else if (in0_p && ! in1_p) |
| { |
| /* If they don't overlap, the result is the first range. If they are |
| equal, the result is false. If the second range is a subset of the |
| first, and the ranges begin at the same place, we go from just after |
| the end of the second range to the end of the first. If the second |
| range is not a subset of the first, or if it is a subset and both |
| ranges end at the same place, the range starts at the start of the |
| first range and ends just before the second range. |
| Otherwise, we can't describe this as a single range. */ |
| if (no_overlap) |
| in_p = 1, low = low0, high = high0; |
| else if (lowequal && highequal) |
| in_p = 0, low = high = 0; |
| else if (subset && lowequal) |
| { |
| low = range_successor (high1); |
| high = high0; |
| in_p = 1; |
| if (low == 0) |
| { |
| /* We are in the weird situation where high0 > high1 but |
| high1 has no successor. Punt. */ |
| return 0; |
| } |
| } |
| else if (! subset || highequal) |
| { |
| low = low0; |
| high = range_predecessor (low1); |
| in_p = 1; |
| if (high == 0) |
| { |
| /* low0 < low1 but low1 has no predecessor. Punt. */ |
| return 0; |
| } |
| } |
| else |
| return 0; |
| } |
| |
| else if (! in0_p && in1_p) |
| { |
| /* If they don't overlap, the result is the second range. If the second |
| is a subset of the first, the result is false. Otherwise, |
| the range starts just after the first range and ends at the |
| end of the second. */ |
| if (no_overlap) |
| in_p = 1, low = low1, high = high1; |
| else if (subset || highequal) |
| in_p = 0, low = high = 0; |
| else |
| { |
| low = range_successor (high0); |
| high = high1; |
| in_p = 1; |
| if (low == 0) |
| { |
| /* high1 > high0 but high0 has no successor. Punt. */ |
| return 0; |
| } |
| } |
| } |
| |
| else |
| { |
| /* The case where we are excluding both ranges. Here the complex case |
| is if they don't overlap. In that case, the only time we have a |
| range is if they are adjacent. If the second is a subset of the |
| first, the result is the first. Otherwise, the range to exclude |
| starts at the beginning of the first range and ends at the end of the |
| second. */ |
| if (no_overlap) |
| { |
| if (integer_onep (range_binop (EQ_EXPR, integer_type_node, |
| range_successor (high0), |
| 1, low1, 0))) |
| in_p = 0, low = low0, high = high1; |
| else |
| { |
| /* Canonicalize - [min, x] into - [-, x]. */ |
| if (low0 && TREE_CODE (low0) == INTEGER_CST) |
| switch (TREE_CODE (TREE_TYPE (low0))) |
| { |
| case ENUMERAL_TYPE: |
| if (maybe_ne (TYPE_PRECISION (TREE_TYPE (low0)), |
| GET_MODE_BITSIZE |
| (TYPE_MODE (TREE_TYPE (low0))))) |
| break; |
| /* FALLTHROUGH */ |
| case INTEGER_TYPE: |
| if (tree_int_cst_equal (low0, |
| TYPE_MIN_VALUE (TREE_TYPE (low0)))) |
| low0 = 0; |
| break; |
| case POINTER_TYPE: |
| if (TYPE_UNSIGNED (TREE_TYPE (low0)) |
| && integer_zerop (low0)) |
| low0 = 0; |
| break; |
| default: |
| break; |
| } |
| |
| /* Canonicalize - [x, max] into - [x, -]. */ |
| if (high1 && TREE_CODE (high1) == INTEGER_CST) |
| switch (TREE_CODE (TREE_TYPE (high1))) |
| { |
| case ENUMERAL_TYPE: |
| if (maybe_ne (TYPE_PRECISION (TREE_TYPE (high1)), |
| GET_MODE_BITSIZE |
| (TYPE_MODE (TREE_TYPE (high1))))) |
| break; |
| /* FALLTHROUGH */ |
| case INTEGER_TYPE: |
| if (tree_int_cst_equal (high1, |
| TYPE_MAX_VALUE (TREE_TYPE (high1)))) |
| high1 = 0; |
| break; |
| case POINTER_TYPE: |
| if (TYPE_UNSIGNED (TREE_TYPE (high1)) |
| && integer_zerop (range_binop (PLUS_EXPR, NULL_TREE, |
| high1, 1, |
| build_int_cst (TREE_TYPE (high1), 1), |
| 1))) |
| high1 = 0; |
| break; |
| default: |
| break; |
| } |
| |
| /* The ranges might be also adjacent between the maximum and |
| minimum values of the given type. For |
| - [{min,-}, x] and - [y, {max,-}] ranges where x + 1 < y |
| return + [x + 1, y - 1]. */ |
| if (low0 == 0 && high1 == 0) |
| { |
| low = range_successor (high0); |
| high = range_predecessor (low1); |
| if (low == 0 || high == 0) |
| return 0; |
| |
| in_p = 1; |
| } |
| else |
| return 0; |
| } |
| } |
| else if (subset) |
| in_p = 0, low = low0, high = high0; |
| else |
| in_p = 0, low = low0, high = high1; |
| } |
| |
| *pin_p = in_p, *plow = low, *phigh = high; |
| return 1; |
| } |
| |
| |
| /* Subroutine of fold, looking inside expressions of the form |
| A op B ? A : C, where (ARG00, COMP_CODE, ARG01), ARG1 and ARG2 |
| are the three operands of the COND_EXPR. This function is |
| being used also to optimize A op B ? C : A, by reversing the |
| comparison first. |
| |
| Return a folded expression whose code is not a COND_EXPR |
| anymore, or NULL_TREE if no folding opportunity is found. */ |
| |
| static tree |
| fold_cond_expr_with_comparison (location_t loc, tree type, |
| enum tree_code comp_code, |
| tree arg00, tree arg01, tree arg1, tree arg2) |
| { |
| tree arg1_type = TREE_TYPE (arg1); |
| tree tem; |
| |
| STRIP_NOPS (arg1); |
| STRIP_NOPS (arg2); |
| |
| /* If we have A op 0 ? A : -A, consider applying the following |
| transformations: |
| |
| A == 0? A : -A same as -A |
| A != 0? A : -A same as A |
| A >= 0? A : -A same as abs (A) |
| A > 0? A : -A same as abs (A) |
| A <= 0? A : -A same as -abs (A) |
| A < 0? A : -A same as -abs (A) |
| |
| None of these transformations work for modes with signed |
| zeros. If A is +/-0, the first two transformations will |
| change the sign of the result (from +0 to -0, or vice |
| versa). The last four will fix the sign of the result, |
| even though the original expressions could be positive or |
| negative, depending on the sign of A. |
| |
| Note that all these transformations are correct if A is |
| NaN, since the two alternatives (A and -A) are also NaNs. */ |
| if (!HONOR_SIGNED_ZEROS (type) |
| && (FLOAT_TYPE_P (TREE_TYPE (arg01)) |
| ? real_zerop (arg01) |
| : integer_zerop (arg01)) |
| && ((TREE_CODE (arg2) == NEGATE_EXPR |
| && operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0)) |
| /* In the case that A is of the form X-Y, '-A' (arg2) may |
| have already been folded to Y-X, check for that. */ |
| || (TREE_CODE (arg1) == MINUS_EXPR |
| && TREE_CODE (arg2) == MINUS_EXPR |
| && operand_equal_p (TREE_OPERAND (arg1, 0), |
| TREE_OPERAND (arg2, 1), 0) |
| && operand_equal_p (TREE_OPERAND (arg1, 1), |
| TREE_OPERAND (arg2, 0), 0)))) |
| switch (comp_code) |
| { |
| case EQ_EXPR: |
| case UNEQ_EXPR: |
| tem = fold_convert_loc (loc, arg1_type, arg1); |
| return fold_convert_loc (loc, type, negate_expr (tem)); |
| case NE_EXPR: |
| case LTGT_EXPR: |
| return fold_convert_loc (loc, type, arg1); |
| case UNGE_EXPR: |
| case UNGT_EXPR: |
| if (flag_trapping_math) |
| break; |
| /* Fall through. */ |
| case GE_EXPR: |
| case GT_EXPR: |
| if (TYPE_UNSIGNED (TREE_TYPE (arg1))) |
| break; |
| tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); |
| return fold_convert_loc (loc, type, tem); |
| case UNLE_EXPR: |
| case UNLT_EXPR: |
| if (flag_trapping_math) |
| break; |
| /* FALLTHRU */ |
| case LE_EXPR: |
| case LT_EXPR: |
| if (TYPE_UNSIGNED (TREE_TYPE (arg1))) |
| break; |
| if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg1)) |
| && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))) |
| { |
| /* A <= 0 ? A : -A for A INT_MIN is valid, but -abs(INT_MIN) |
| is not, invokes UB both in abs and in the negation of it. |
| So, use ABSU_EXPR instead. */ |
| tree utype = unsigned_type_for (TREE_TYPE (arg1)); |
| tem = fold_build1_loc (loc, ABSU_EXPR, utype, arg1); |
| tem = negate_expr (tem); |
| return fold_convert_loc (loc, type, tem); |
| } |
| else |
| { |
| tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); |
| return negate_expr (fold_convert_loc (loc, type, tem)); |
| } |
| default: |
| gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison); |
| break; |
| } |
| |
| /* A != 0 ? A : 0 is simply A, unless A is -0. Likewise |
| A == 0 ? A : 0 is always 0 unless A is -0. Note that |
| both transformations are correct when A is NaN: A != 0 |
| is then true, and A == 0 is false. */ |
| |
| if (!HONOR_SIGNED_ZEROS (type) |
| && integer_zerop (arg01) && integer_zerop (arg2)) |
| { |
| if (comp_code == NE_EXPR) |
| return fold_convert_loc (loc, type, arg1); |
| else if (comp_code == EQ_EXPR) |
| return build_zero_cst (type); |
| } |
| |
| /* Try some transformations of A op B ? A : B. |
| |
| A == B? A : B same as B |
| A != B? A : B same as A |
| A >= B? A : B same as max (A, B) |
| A > B? A : B same as max (B, A) |
| A <= B? A : B same as min (A, B) |
| A < B? A : B same as min (B, A) |
| |
| As above, these transformations don't work in the presence |
| of signed zeros. For example, if A and B are zeros of |
| opposite sign, the first two transformations will change |
| the sign of the result. In the last four, the original |
| expressions give different results for (A=+0, B=-0) and |
| (A=-0, B=+0), but the transformed expressions do not. |
| |
| The first two transformations are correct if either A or B |
| is a NaN. In the first transformation, the condition will |
| be false, and B will indeed be chosen. In the case of the |
| second transformation, the condition A != B will be true, |
| and A will be chosen. |
| |
| The conversions to max() and min() are not correct if B is |
| a number and A is not. The conditions in the original |
| expressions will be false, so all four give B. The min() |
| and max() versions would give a NaN instead. */ |
| if (!HONOR_SIGNED_ZEROS (type) |
| && operand_equal_for_comparison_p (arg01, arg2) |
| /* Avoid these transformations if the COND_EXPR may be used |
| as an lvalue in the C++ front-end. PR c++/19199. */ |
| && (in_gimple_form |
| || VECTOR_TYPE_P (type) |
| || (! lang_GNU_CXX () |
| && strcmp (lang_hooks.name, "GNU Objective-C++") != 0) |
| || ! maybe_lvalue_p (arg1) |
| || ! maybe_lvalue_p (arg2))) |
| { |
| tree comp_op0 = arg00; |
| tree comp_op1 = arg01; |
| tree comp_type = TREE_TYPE (comp_op0); |
| |
| switch (comp_code) |
| { |
| case EQ_EXPR: |
| return fold_convert_loc (loc, type, arg2); |
| case NE_EXPR: |
| return fold_convert_loc (loc, type, arg1); |
| case LE_EXPR: |
| case LT_EXPR: |
| case UNLE_EXPR: |
| case UNLT_EXPR: |
| /* In C++ a ?: expression can be an lvalue, so put the |
| 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 (arg1)) |
| { |
| comp_op0 = fold_convert_loc (loc, comp_type, comp_op0); |
| comp_op1 = fold_convert_loc (loc, comp_type, comp_op1); |
| tem = (comp_code == LE_EXPR || comp_code == UNLE_EXPR) |
| ? fold_build2_loc (loc, MIN_EXPR, comp_type, comp_op0, comp_op1) |
| : fold_build2_loc (loc, MIN_EXPR, comp_type, |
| comp_op1, comp_op0); |
| return fold_convert_loc (loc, type, tem); |
| } |
| break; |
| case GE_EXPR: |
| case GT_EXPR: |
| case UNGE_EXPR: |
| case UNGT_EXPR: |
| if (!HONOR_NANS (arg1)) |
| { |
| comp_op0 = fold_convert_loc (loc, comp_type, comp_op0); |
| comp_op1 = fold_convert_loc (loc, comp_type, comp_op1); |
| tem = (comp_code == GE_EXPR || comp_code == UNGE_EXPR) |
| ? fold_build2_loc (loc, MAX_EXPR, comp_type, comp_op0, comp_op1) |
| : fold_build2_loc (loc, MAX_EXPR, comp_type, |
| comp_op1, comp_op0); |
| return fold_convert_loc (loc, type, tem); |
| } |
| break; |
| case UNEQ_EXPR: |
| if (!HONOR_NANS (arg1)) |
| return fold_convert_loc (loc, type, arg2); |
| break; |
| case LTGT_EXPR: |
| if (!HONOR_NANS (arg1)) |
| return fold_convert_loc (loc, type, arg1); |
| break; |
| default: |
| gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison); |
| break; |
| } |
| } |
| |
| return NULL_TREE; |
| } |
| |
| |
| |
| #ifndef LOGICAL_OP_NON_SHORT_CIRCUIT |
| #define LOGICAL_OP_NON_SHORT_CIRCUIT \ |
| (BRANCH_COST (optimize_function_for_speed_p (cfun), \ |
| false) >= 2) |
| #endif |
| |
| /* EXP is some logical combination of boolean tests. See if we can |
| merge it into some range test. Return the new tree if so. */ |
| |
| static tree |
| fold_range_test (location_t loc, enum tree_code code, tree type, |
| tree op0, tree op1) |
| { |
| int or_op = (code == TRUTH_ORIF_EXPR |
| || code == TRUTH_OR_EXPR); |
| int in0_p, in1_p, in_p; |
| tree low0, low1, low, high0, high1, high; |
| bool strict_overflow_p = false; |
| tree tem, lhs, rhs; |
| const char * const warnmsg = G_("assuming signed overflow does not occur " |
| "when simplifying range test"); |
| |
| if (!INTEGRAL_TYPE_P (type)) |
| return 0; |
| |
| lhs = make_range (op0, &in0_p, &low0, &high0, &strict_overflow_p); |
| /* If op0 is known true or false and this is a short-circuiting |
| operation we must not merge with op1 since that makes side-effects |
| unconditional. So special-case this. */ |
| if (!lhs |
| && ((code == TRUTH_ORIF_EXPR && in0_p) |
| || (code == TRUTH_ANDIF_EXPR && !in0_p))) |
| return op0; |
| rhs = make_range (op1, &in1_p, &low1, &high1, &strict_overflow_p); |
| |
| /* If this is an OR operation, invert both sides; we will invert |
| again at the end. */ |
| if (or_op) |
| in0_p = ! in0_p, in1_p = ! in1_p; |
| |
| /* If both expressions are the same, if we can merge the ranges, and we |
| can build the range test, return it or it inverted. If one of the |
| ranges is always true or always false, consider it to be the same |
| expression as the other. */ |
| if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0)) |
| && merge_ranges (&in_p, &low, &high, in0_p, low0, high0, |
| in1_p, low1, high1) |
| && (tem = (build_range_check (loc, type, |
| lhs != 0 ? lhs |
| : rhs != 0 ? rhs : integer_zero_node, |
| in_p, low, high))) != 0) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); |
| return or_op ? invert_truthvalue_loc (loc, tem) : tem; |
| } |
| |
| /* On machines where the branch cost is expensive, if this is a |
| short-circuited branch and the underlying object on both sides |
| is the same, make a non-short-circuit operation. */ |
| bool logical_op_non_short_circuit = LOGICAL_OP_NON_SHORT_CIRCUIT; |
| if (param_logical_op_non_short_circuit != -1) |
| logical_op_non_short_circuit |
| = param_logical_op_non_short_circuit; |
| if (logical_op_non_short_circuit |
| && !sanitize_coverage_p () |
| && lhs != 0 && rhs != 0 |
| && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR) |
| && operand_equal_p (lhs, rhs, 0)) |
| { |
| /* If simple enough, just rewrite. Otherwise, make a SAVE_EXPR |
| unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in |
| which cases we can't do this. */ |
| if (simple_operand_p (lhs)) |
| return build2_loc (loc, code == TRUTH_ANDIF_EXPR |
| ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, |
| type, op0, op1); |
| |
| else if (!lang_hooks.decls.global_bindings_p () |
| && !CONTAINS_PLACEHOLDER_P (lhs)) |
| { |
| tree common = save_expr (lhs); |
| |
| if ((lhs = build_range_check (loc, type, common, |
| or_op ? ! in0_p : in0_p, |
| low0, high0)) != 0 |
| && (rhs = build_range_check (loc, type, common, |
| or_op ? ! in1_p : in1_p, |
| low1, high1)) != 0) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (warnmsg, |
| WARN_STRICT_OVERFLOW_COMPARISON); |
| return build2_loc (loc, code == TRUTH_ANDIF_EXPR |
| ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, |
| type, lhs, rhs); |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| /* Subroutine for fold_truth_andor_1: C is an INTEGER_CST interpreted as a P |
| bit value. Arrange things so the extra bits will be set to zero if and |
| only if C is signed-extended to its full width. If MASK is nonzero, |
| it is an INTEGER_CST that should be AND'ed with the extra bits. */ |
| |
| static tree |
| unextend (tree c, int p, int unsignedp, tree mask) |
| { |
| tree type = TREE_TYPE (c); |
| int modesize = GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type)); |
| tree temp; |
| |
| if (p == modesize || unsignedp) |
| return c; |
| |
| /* We work by getting just the sign bit into the low-order bit, then |
| into the high-order bit, then sign-extend. We then XOR that value |
| with C. */ |
| temp = build_int_cst (TREE_TYPE (c), |
| wi::extract_uhwi (wi::to_wide (c), p - 1, 1)); |
| |
| /* We must use a signed type in order to get an arithmetic right shift. |
| However, we must also avoid introducing accidental overflows, so that |
| a subsequent call to integer_zerop will work. Hence we must |
| do the type conversion here. At this point, the constant is either |
| zero or one, and the conversion to a signed type can never overflow. |
| We could get an overflow if this conversion is done anywhere else. */ |
| if (TYPE_UNSIGNED (type)) |
| temp = fold_convert (signed_type_for (type), temp); |
| |
| temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1)); |
| temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1)); |
| if (mask != 0) |
| temp = const_binop (BIT_AND_EXPR, temp, |
| fold_convert (TREE_TYPE (c), mask)); |
| /* If necessary, convert the type back to match the type of C. */ |
| if (TYPE_UNSIGNED (type)) |
| temp = fold_convert (type, temp); |
| |
| return fold_convert (type, const_binop (BIT_XOR_EXPR, c, temp)); |
| } |
| |
| /* For an expression that has the form |
| (A && B) || ~B |
| or |
| (A || B) && ~B, |
| we can drop one of the inner expressions and simplify to |
| A || ~B |
| or |
| A && ~B |
| LOC is the location of the resulting expression. OP is the inner |
| logical operation; the left-hand side in the examples above, while CMPOP |
| is the right-hand side. RHS_ONLY is used to prevent us from accidentally |
| removing a condition that guards another, as in |
| (A != NULL && A->...) || A == NULL |
| which we must not transform. If RHS_ONLY is true, only eliminate the |
| right-most operand of the inner logical operation. */ |
| |
| static tree |
| merge_truthop_with_opposite_arm (location_t loc, tree op, tree cmpop, |
| bool rhs_only) |
| { |
| tree type = TREE_TYPE (cmpop); |
| enum tree_code code = TREE_CODE (cmpop); |
| enum tree_code truthop_code = TREE_CODE (op); |
| tree lhs = TREE_OPERAND (op, 0); |
| tree rhs = TREE_OPERAND (op, 1); |
| tree orig_lhs = lhs, orig_rhs = rhs; |
| enum tree_code rhs_code = TREE_CODE (rhs); |
| enum tree_code lhs_code = TREE_CODE (lhs); |
| enum tree_code inv_code; |
| |
| if (TREE_SIDE_EFFECTS (op) || TREE_SIDE_EFFECTS (cmpop)) |
| return NULL_TREE; |
| |
| if (TREE_CODE_CLASS (code) != tcc_comparison) |
| return NULL_TREE; |
| |
| if (rhs_code == truthop_code) |
| { |
| tree newrhs = merge_truthop_with_opposite_arm (loc, rhs, cmpop, rhs_only); |
| if (newrhs != NULL_TREE) |
| { |
| rhs = newrhs; |
| rhs_code = TREE_CODE (rhs); |
| } |
| } |
| if (lhs_code == truthop_code && !rhs_only) |
| { |
| tree newlhs = merge_truthop_with_opposite_arm (loc, lhs, cmpop, false); |
| if (newlhs != NULL_TREE) |
| { |
| lhs = newlhs; |
| lhs_code = TREE_CODE (lhs); |
| } |
| } |
| |
| 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)) |
| return lhs; |
| if (!rhs_only && inv_code == lhs_code |
| && operand_equal_p (TREE_OPERAND (lhs, 0), TREE_OPERAND (cmpop, 0), 0) |
| && operand_equal_p (TREE_OPERAND (lhs, 1), TREE_OPERAND (cmpop, 1), 0)) |
| return rhs; |
| if (rhs != orig_rhs || lhs != orig_lhs) |
| return fold_build2_loc (loc, truthop_code, TREE_TYPE (cmpop), |
| lhs, rhs); |
| return NULL_TREE; |
| } |
| |
| /* Find ways of folding logical expressions of LHS and RHS: |
| Try to merge two comparisons to the same innermost item. |
| Look for range tests like "ch >= '0' && ch <= '9'". |
| Look for combinations of simple terms on machines with expensive branches |
| and evaluate the RHS unconditionally. |
| |
| For example, if we have p->a == 2 && p->b == 4 and we can make an |
| object large enough to span both A and B, we can do this with a comparison |
| against the object ANDed with the a mask. |
| |
| If we have p->a == q->a && p->b == q->b, we may be able to use bit masking |
| operations to do this with one comparison. |
| |
| We check for both normal comparisons and the BIT_AND_EXPRs made this by |
| function and the one above. |
| |
| CODE is the logical operation being done. It can be TRUTH_ANDIF_EXPR, |
| TRUTH_AND_EXPR, TRUTH_ORIF_EXPR, or TRUTH_OR_EXPR. |
| |
| TRUTH_TYPE is the type of the logical operand and LHS and RHS are its |
| two operands. |
| |
| We return the simplified tree or 0 if no optimization is possible. */ |
| |
| static tree |
| fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type, |
| tree lhs, tree rhs) |
| { |
| /* If this is the "or" of two comparisons, we can do something if |
| the comparisons are NE_EXPR. If this is the "and", we can do something |
| if the comparisons are EQ_EXPR. I.e., |
| (a->b == 2 && a->c == 4) can become (a->new == NEW). |
| |
| WANTED_CODE is this operation code. For single bit fields, we can |
| convert EQ_EXPR to NE_EXPR so we need not reject the "wrong" |
| comparison for one-bit fields. */ |
| |
| enum tree_code wanted_code; |
| enum tree_code lcode, rcode; |
| tree ll_arg, lr_arg, rl_arg, rr_arg; |
| tree ll_inner, lr_inner, rl_inner, rr_inner; |
| HOST_WIDE_INT ll_bitsize, ll_bitpos, lr_bitsize, lr_bitpos; |
| HOST_WIDE_INT rl_bitsize, rl_bitpos, rr_bitsize, rr_bitpos; |
| HOST_WIDE_INT xll_bitpos, xlr_bitpos, xrl_bitpos, xrr_bitpos; |
| HOST_WIDE_INT lnbitsize, lnbitpos, rnbitsize, rnbitpos; |
| int ll_unsignedp, lr_unsignedp, rl_unsignedp, rr_unsignedp; |
| int ll_reversep, lr_reversep, rl_reversep, rr_reversep; |
| machine_mode ll_mode, lr_mode, rl_mode, rr_mode; |
| scalar_int_mode lnmode, rnmode; |
| tree ll_mask, lr_mask, rl_mask, rr_mask; |
| tree ll_and_mask, lr_and_mask, rl_and_mask, rr_and_mask; |
| tree l_const, r_const; |
| tree lntype, rntype, result; |
| HOST_WIDE_INT first_bit, end_bit; |
| int volatilep; |
| |
| /* Start by getting the comparison codes. Fail if anything is volatile. |
| If one operand is a BIT_AND_EXPR with the constant one, treat it as if |
| it were surrounded with a NE_EXPR. */ |
| |
| if (TREE_SIDE_EFFECTS (lhs) || TREE_SIDE_EFFECTS (rhs)) |
| return 0; |
| |
| lcode = TREE_CODE (lhs); |
| rcode = TREE_CODE (rhs); |
| |
| if (lcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (lhs, 1))) |
| { |
| lhs = build2 (NE_EXPR, truth_type, lhs, |
| build_int_cst (TREE_TYPE (lhs), 0)); |
| lcode = NE_EXPR; |
| } |
| |
| if (rcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (rhs, 1))) |
| { |
| rhs = build2 (NE_EXPR, truth_type, rhs, |
| build_int_cst (TREE_TYPE (rhs), 0)); |
| rcode = NE_EXPR; |
| } |
| |
| if (TREE_CODE_CLASS (lcode) != tcc_comparison |
| || TREE_CODE_CLASS (rcode) != tcc_comparison) |
| return 0; |
| |
| ll_arg = TREE_OPERAND (lhs, 0); |
| lr_arg = TREE_OPERAND (lhs, 1); |
| rl_arg = TREE_OPERAND (rhs, 0); |
| rr_arg = TREE_OPERAND (rhs, 1); |
| |
| /* Simplify (x<y) && (x==y) into (x<=y) and related optimizations. */ |
| if (simple_operand_p (ll_arg) |
| && simple_operand_p (lr_arg)) |
| { |
| if (operand_equal_p (ll_arg, rl_arg, 0) |
| && operand_equal_p (lr_arg, rr_arg, 0)) |
| { |
| result = combine_comparisons (loc, code, lcode, rcode, |
| truth_type, ll_arg, lr_arg); |
| if (result) |
| return result; |
| } |
| else if (operand_equal_p (ll_arg, rr_arg, 0) |
| && operand_equal_p (lr_arg, rl_arg, 0)) |
| { |
| result = combine_comparisons (loc, code, lcode, |
| swap_tree_comparison (rcode), |
| truth_type, ll_arg, lr_arg); |
| if (result) |
| return result; |
| } |
| } |
| |
| code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR) |
| ? TRUTH_AND_EXPR : TRUTH_OR_EXPR); |
| |
| /* If the RHS can be evaluated unconditionally and its operands are |
| simple, it wins to evaluate the RHS unconditionally on machines |
| with expensive branches. In this case, this isn't a comparison |
| that can be merged. */ |
| |
| if (BRANCH_COST (optimize_function_for_speed_p (cfun), |
| false) >= 2 |
| && ! FLOAT_TYPE_P (TREE_TYPE (rl_arg)) |
| && simple_operand_p (rl_arg) |
| && simple_operand_p (rr_arg)) |
| { |
| /* Convert (a != 0) || (b != 0) into (a | b) != 0. */ |
| if (code == TRUTH_OR_EXPR |
| && lcode == NE_EXPR && integer_zerop (lr_arg) |
| && rcode == NE_EXPR && integer_zerop (rr_arg) |
| && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg) |
| && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg))) |
| return build2_loc (loc, NE_EXPR, truth_type, |
| build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg), |
| ll_arg, rl_arg), |
| build_int_cst (TREE_TYPE (ll_arg), 0)); |
| |
| /* Convert (a == 0) && (b == 0) into (a | b) == 0. */ |
| if (code == TRUTH_AND_EXPR |
| && lcode == EQ_EXPR && integer_zerop (lr_arg) |
| && rcode == EQ_EXPR && integer_zerop (rr_arg) |
| && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg) |
| && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg))) |
| return build2_loc (loc, EQ_EXPR, truth_type, |
| build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg), |
| ll_arg, rl_arg), |
| build_int_cst (TREE_TYPE (ll_arg), 0)); |
| } |
| |
| /* See if the comparisons can be merged. Then get all the parameters for |
| each side. */ |
| |
| if ((lcode != EQ_EXPR && lcode != NE_EXPR) |
| || (rcode != EQ_EXPR && rcode != NE_EXPR)) |
| return 0; |
| |
| ll_reversep = lr_reversep = rl_reversep = rr_reversep = 0; |
| volatilep = 0; |
| ll_inner = decode_field_reference (loc, &ll_arg, |
| &ll_bitsize, &ll_bitpos, &ll_mode, |
| &ll_unsignedp, &ll_reversep, &volatilep, |
| &ll_mask, &ll_and_mask); |
| lr_inner = decode_field_reference (loc, &lr_arg, |
| &lr_bitsize, &lr_bitpos, &lr_mode, |
| &lr_unsignedp, &lr_reversep, &volatilep, |
| &lr_mask, &lr_and_mask); |
| rl_inner = decode_field_reference (loc, &rl_arg, |
| &rl_bitsize, &rl_bitpos, &rl_mode, |
| &rl_unsignedp, &rl_reversep, &volatilep, |
| &rl_mask, &rl_and_mask); |
| rr_inner = decode_field_reference (loc, &rr_arg, |
| &rr_bitsize, &rr_bitpos, &rr_mode, |
| &rr_unsignedp, &rr_reversep, &volatilep, |
| &rr_mask, &rr_and_mask); |
| |
| /* It must be true that the inner operation on the lhs of each |
| comparison must be the same if we are to be able to do anything. |
| Then see if we have constants. If not, the same must be true for |
| the rhs's. */ |
| if (volatilep |
| || ll_reversep != rl_reversep |
| || ll_inner == 0 || rl_inner == 0 |
| || ! operand_equal_p (ll_inner, rl_inner, 0)) |
| return 0; |
| |
| if (TREE_CODE (lr_arg) == INTEGER_CST |
| && TREE_CODE (rr_arg) == INTEGER_CST) |
| { |
| l_const = lr_arg, r_const = rr_arg; |
| lr_reversep = ll_reversep; |
| } |
| else if (lr_reversep != rr_reversep |
| || lr_inner == 0 || rr_inner == 0 |
| || ! operand_equal_p (lr_inner, rr_inner, 0)) |
| return 0; |
| else |
| l_const = r_const = 0; |
| |
| /* If either comparison code is not correct for our logical operation, |
| fail. However, we can convert a one-bit comparison against zero into |
| the opposite comparison against that bit being set in the field. */ |
| |
| wanted_code = (code == TRUTH_AND_EXPR ? EQ_EXPR : NE_EXPR); |
| if (lcode != wanted_code) |
| { |
| if (l_const && integer_zerop (l_const) && integer_pow2p (ll_mask)) |
| { |
| /* Make the left operand unsigned, since we are only interested |
| in the value of one bit. Otherwise we are doing the wrong |
| thing below. */ |
| ll_unsignedp = 1; |
| l_const = ll_mask; |
| } |
| else |
| return 0; |
| } |
| |
| /* This is analogous to the code for l_const above. */ |
| if (rcode != wanted_code) |
| { |
| if (r_const && integer_zerop (r_const) && integer_pow2p (rl_mask)) |
| { |
| rl_unsignedp = 1; |
| r_const = rl_mask; |
| } |
| else |
| return 0; |
| } |
| |
| /* See if we can find a mode that contains both fields being compared on |
| the left. If we can't, fail. Otherwise, update all constants and masks |
| to be relative to a field of that size. */ |
| first_bit = MIN (ll_bitpos, rl_bitpos); |
| end_bit = MAX (ll_bitpos + ll_bitsize, rl_bitpos + rl_bitsize); |
| if (!get_best_mode (end_bit - first_bit, first_bit, 0, 0, |
| TYPE_ALIGN (TREE_TYPE (ll_inner)), BITS_PER_WORD, |
| volatilep, &lnmode)) |
| return 0; |
| |
| lnbitsize = GET_MODE_BITSIZE (lnmode); |
| lnbitpos = first_bit & ~ (lnbitsize - 1); |
| lntype = lang_hooks.types.type_for_size (lnbitsize, 1); |
| xll_bitpos = ll_bitpos - lnbitpos, xrl_bitpos = rl_bitpos - lnbitpos; |
| |
| if (ll_reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) |
| { |
| xll_bitpos = lnbitsize - xll_bitpos - ll_bitsize; |
| xrl_bitpos = lnbitsize - xrl_bitpos - rl_bitsize; |
| } |
| |
| ll_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, lntype, ll_mask), |
| size_int (xll_bitpos)); |
| rl_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, lntype, rl_mask), |
| size_int (xrl_bitpos)); |
| |
| if (l_const) |
| { |
| l_const = fold_convert_loc (loc, lntype, l_const); |
| l_const = unextend (l_const, ll_bitsize, ll_unsignedp, ll_and_mask); |
| l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos)); |
| if (! integer_zerop (const_binop (BIT_AND_EXPR, l_const, |
| fold_build1_loc (loc, BIT_NOT_EXPR, |
| lntype, ll_mask)))) |
| { |
| warning (0, "comparison is always %d", wanted_code == NE_EXPR); |
| |
| return constant_boolean_node (wanted_code == NE_EXPR, truth_type); |
| } |
| } |
| if (r_const) |
| { |
| r_const = fold_convert_loc (loc, lntype, r_const); |
| r_const = unextend (r_const, rl_bitsize, rl_unsignedp, rl_and_mask); |
| r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos)); |
| if (! integer_zerop (const_binop (BIT_AND_EXPR, r_const, |
| fold_build1_loc (loc, BIT_NOT_EXPR, |
| lntype, rl_mask)))) |
| { |
| warning (0, "comparison is always %d", wanted_code == NE_EXPR); |
| |
| return constant_boolean_node (wanted_code == NE_EXPR, truth_type); |
| } |
| } |
| |
| /* If the right sides are not constant, do the same for it. Also, |
| disallow this optimization if a size, signedness or storage order |
| mismatch occurs between the left and right sides. */ |
| if (l_const == 0) |
| { |
| if (ll_bitsize != lr_bitsize || rl_bitsize != rr_bitsize |
| || ll_unsignedp != lr_unsignedp || rl_unsignedp != rr_unsignedp |
| || ll_reversep != lr_reversep |
| /* Make sure the two fields on the right |
| correspond to the left without being swapped. */ |
| || ll_bitpos - rl_bitpos != lr_bitpos - rr_bitpos) |
| return 0; |
| |
| first_bit = MIN (lr_bitpos, rr_bitpos); |
| end_bit = MAX (lr_bitpos + lr_bitsize, rr_bitpos + rr_bitsize); |
| if (!get_best_mode (end_bit - first_bit, first_bit, 0, 0, |
| TYPE_ALIGN (TREE_TYPE (lr_inner)), BITS_PER_WORD, |
| volatilep, &rnmode)) |
| return 0; |
| |
| rnbitsize = GET_MODE_BITSIZE (rnmode); |
| rnbitpos = first_bit & ~ (rnbitsize - 1); |
| rntype = lang_hooks.types.type_for_size (rnbitsize, 1); |
| xlr_bitpos = lr_bitpos - rnbitpos, xrr_bitpos = rr_bitpos - rnbitpos; |
| |
| if (lr_reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) |
| { |
| xlr_bitpos = rnbitsize - xlr_bitpos - lr_bitsize; |
| xrr_bitpos = rnbitsize - xrr_bitpos - rr_bitsize; |
| } |
| |
| lr_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, |
| rntype, lr_mask), |
| size_int (xlr_bitpos)); |
| rr_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, |
| rntype, rr_mask), |
| size_int (xrr_bitpos)); |
| |
| /* Make a mask that corresponds to both fields being compared. |
| Do this for both items being compared. If the operands are the |
| same size and the bits being compared are in the same position |
| then we can do this by masking both and comparing the masked |
| results. */ |
| ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask); |
| lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask); |
| if (lnbitsize == rnbitsize |
| && xll_bitpos == xlr_bitpos |
| && lnbitpos >= 0 |
| && rnbitpos >= 0) |
| { |
| lhs = make_bit_field_ref (loc, ll_inner, ll_arg, |
| lntype, lnbitsize, lnbitpos, |
| ll_unsignedp || rl_unsignedp, ll_reversep); |
| if (! all_ones_mask_p (ll_mask, lnbitsize)) |
| lhs = build2 (BIT_AND_EXPR, lntype, lhs, ll_mask); |
| |
| rhs = make_bit_field_ref (loc, lr_inner, lr_arg, |
| rntype, rnbitsize, rnbitpos, |
| lr_unsignedp || rr_unsignedp, lr_reversep); |
| if (! all_ones_mask_p (lr_mask, rnbitsize)) |
| rhs = build2 (BIT_AND_EXPR, rntype, rhs, lr_mask); |
| |
| return build2_loc (loc, wanted_code, truth_type, lhs, rhs); |
| } |
| |
| /* There is still another way we can do something: If both pairs of |
| fields being compared are adjacent, we may be able to make a wider |
| field containing them both. |
| |
| Note that we still must mask the lhs/rhs expressions. Furthermore, |
| the mask must be shifted to account for the shift done by |
| make_bit_field_ref. */ |
| if (((ll_bitsize + ll_bitpos == rl_bitpos |
| && lr_bitsize + lr_bitpos == rr_bitpos) |
| || (ll_bitpos == rl_bitpos + rl_bitsize |
| && lr_bitpos == rr_bitpos + rr_bitsize)) |
| && ll_bitpos >= 0 |
| && rl_bitpos >= 0 |
| && lr_bitpos >= 0 |
| && rr_bitpos >= 0) |
| { |
| tree type; |
| |
| lhs = make_bit_field_ref (loc, ll_inner, ll_arg, lntype, |
| ll_bitsize + rl_bitsize, |
| MIN (ll_bitpos, rl_bitpos), |
| ll_unsignedp, ll_reversep); |
| rhs = make_bit_field_ref (loc, lr_inner, lr_arg, rntype, |
| lr_bitsize + rr_bitsize, |
| MIN (lr_bitpos, rr_bitpos), |
| lr_unsignedp, lr_reversep); |
| |
| ll_mask = const_binop (RSHIFT_EXPR, ll_mask, |
| size_int (MIN (xll_bitpos, xrl_bitpos))); |
| lr_mask = const_binop (RSHIFT_EXPR, lr_mask, |
| size_int (MIN (xlr_bitpos, xrr_bitpos))); |
| |
| /* Convert to the smaller type before masking out unwanted bits. */ |
| type = lntype; |
| if (lntype != rntype) |
| { |
| if (lnbitsize > rnbitsize) |
| { |
| lhs = fold_convert_loc (loc, rntype, lhs); |
| ll_mask = fold_convert_loc (loc, rntype, ll_mask); |
| type = rntype; |
| } |
| else if (lnbitsize < rnbitsize) |
| { |
| rhs = fold_convert_loc (loc, lntype, rhs); |
| lr_mask = fold_convert_loc (loc, lntype, lr_mask); |
| type = lntype; |
| } |
| } |
| |
| if (! all_ones_mask_p (ll_mask, ll_bitsize + rl_bitsize)) |
| lhs = build2 (BIT_AND_EXPR, type, lhs, ll_mask); |
| |
| if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize)) |
| rhs = build2 (BIT_AND_EXPR, type, rhs, lr_mask); |
| |
| return build2_loc (loc, wanted_code, truth_type, lhs, rhs); |
| } |
| |
| return 0; |
| } |
| |
| /* Handle the case of comparisons with constants. If there is something in |
| common between the masks, those bits of the constants must be the same. |
| If not, the condition is always false. Test for this to avoid generating |
| incorrect code below. */ |
| result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask); |
| if (! integer_zerop (result) |
| && simple_cst_equal (const_binop (BIT_AND_EXPR, result, l_const), |
| const_binop (BIT_AND_EXPR, result, r_const)) != 1) |
| { |
| if (wanted_code == NE_EXPR) |
| { |
| warning (0, "%<or%> of unmatched not-equal tests is always 1"); |
| return constant_boolean_node (true, truth_type); |
| } |
| else |
| { |
| warning (0, "%<and%> of mutually exclusive equal-tests is always 0"); |
| return constant_boolean_node (false, truth_type); |
| } |
| } |
| |
| if (lnbitpos < 0) |
| return 0; |
| |
| /* Construct the expression we will return. First get the component |
| reference we will make. Unless the mask is all ones the width of |
| that field, perform the mask operation. Then compare with the |
| merged constant. */ |
| result = make_bit_field_ref (loc, ll_inner, ll_arg, |
| lntype, lnbitsize, lnbitpos, |
| ll_unsignedp || rl_unsignedp, ll_reversep); |
| |
| ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask); |
| if (! all_ones_mask_p (ll_mask, lnbitsize)) |
| result = build2_loc (loc, BIT_AND_EXPR, lntype, result, ll_mask); |
| |
| return build2_loc (loc, wanted_code, truth_type, result, |
| const_binop (BIT_IOR_EXPR, l_const, r_const)); |
| } |
| |
| /* T is an integer expression that is being multiplied, divided, or taken a |
| modulus (CODE says which and what kind of divide or modulus) by a |
| constant C. See if we can eliminate that operation by folding it with |
| other operations already in T. WIDE_TYPE, if non-null, is a type that |
| should be used for the computation if wider than our type. |
| |
| For example, if we are dividing (X * 8) + (Y * 16) by 4, we can return |
| (X * 2) + (Y * 4). We must, however, be assured that either the original |
| expression would not overflow or that overflow is undefined for the type |
| in the language in question. |
| |
| If we return a non-null expression, it is an equivalent form of the |
| original computation, but need not be in the original type. |
| |
| We set *STRICT_OVERFLOW_P to true if the return values depends on |
| signed overflow being undefined. Otherwise we do not change |
| *STRICT_OVERFLOW_P. */ |
| |
| static tree |
| extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type, |
| bool *strict_overflow_p) |
| { |
| /* To avoid exponential search depth, refuse to allow recursion past |
| three levels. Beyond that (1) it's highly unlikely that we'll find |
| something interesting and (2) we've probably processed it before |
| when we built the inner expression. */ |
| |
| static int depth; |
| tree ret; |
| |
| if (depth > 3) |
| return NULL; |
| |
| depth++; |
| ret = extract_muldiv_1 (t, c, code, wide_type, strict_overflow_p); |
| depth--; |
| |
| return ret; |
| } |
| |
| static tree |
| extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type, |
| bool *strict_overflow_p) |
| { |
| tree type = TREE_TYPE (t); |
| enum tree_code tcode = TREE_CODE (t); |
| tree ctype = (wide_type != 0 |
| && (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (wide_type)) |
| > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type))) |
| ? wide_type : type); |
| tree t1, t2; |
| int same_p = tcode == code; |
| tree op0 = NULL_TREE, op1 = NULL_TREE; |
| bool sub_strict_overflow_p; |
| |
| /* Don't deal with constants of zero here; they confuse the code below. */ |
| if (integer_zerop (c)) |
| return NULL_TREE; |
| |
| if (TREE_CODE_CLASS (tcode) == tcc_unary) |
| op0 = TREE_OPERAND (t, 0); |
| |
| if (TREE_CODE_CLASS (tcode) == tcc_binary) |
| op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1); |
| |
| /* Note that we need not handle conditional operations here since fold |
| already handles those cases. So just do arithmetic here. */ |
| switch (tcode) |
| { |
| case INTEGER_CST: |
| /* For a constant, we can always simplify if we are a multiply |
| or (for divide and modulus) if it is a multiple of our constant. */ |
| if (code == MULT_EXPR |
| || wi::multiple_of_p (wi::to_wide (t), wi::to_wide (c), |
| TYPE_SIGN (type))) |
| { |
| tree tem = const_binop (code, fold_convert (ctype, t), |
| fold_convert (ctype, c)); |
| /* If the multiplication overflowed, we lost information on it. |
| See PR68142 and PR69845. */ |
| if (TREE_OVERFLOW (tem)) |
| return NULL_TREE; |
| return tem; |
| } |
| break; |
| |
| CASE_CONVERT: case NON_LVALUE_EXPR: |
| if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))) |
| break; |
| /* If op0 is an expression ... */ |
| if ((COMPARISON_CLASS_P (op0) |
| || UNARY_CLASS_P (op0) |
| || BINARY_CLASS_P (op0) |
| || VL_EXP_CLASS_P (op0) |
| || 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)) |
| && (TYPE_PRECISION (ctype) |
| > TYPE_PRECISION (TREE_TYPE (op0)))) |
| /* ... or this is a truncation (t is narrower than op0), |
| then we cannot pass through this narrowing. */ |
| || (TYPE_PRECISION (type) |
| < TYPE_PRECISION (TREE_TYPE (op0))) |
| /* ... or signedness changes for division or modulus, |
| then we cannot pass through this conversion. */ |
| || (code != MULT_EXPR |
| && (TYPE_UNSIGNED (ctype) |
| != TYPE_UNSIGNED (TREE_TYPE (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)) |
| && !TYPE_OVERFLOW_UNDEFINED (type)))) |
| break; |
| |
| /* Pass the constant down and see if we can make a simplification. If |
| we can, replace this expression with the inner simplification for |
| possible later conversion to our or some other type. */ |
| if ((t2 = fold_convert (TREE_TYPE (op0), c)) != 0 |
| && TREE_CODE (t2) == INTEGER_CST |
| && !TREE_OVERFLOW (t2) |
| && (t1 = extract_muldiv (op0, t2, code, |
| code == MULT_EXPR ? ctype : NULL_TREE, |
| strict_overflow_p)) != 0) |
| return t1; |
| break; |
| |
| case ABS_EXPR: |
| /* If widening the type changes it from signed to unsigned, then we |
| must avoid building ABS_EXPR itself as unsigned. */ |
| if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (type)) |
| { |
| tree cstype = (*signed_type_for) (ctype); |
| if ((t1 = extract_muldiv (op0, c, code, cstype, strict_overflow_p)) |
| != 0) |
| { |
| t1 = fold_build1 (tcode, cstype, fold_convert (cstype, t1)); |
| return fold_convert (ctype, t1); |
| } |
| break; |
| } |
| /* If the constant is negative, we cannot simplify this. */ |
| if (tree_int_cst_sgn (c) == -1) |
| break; |
| /* FALLTHROUGH */ |
| case NEGATE_EXPR: |
| /* For division and modulus, type can't be unsigned, as e.g. |
| (-(x / 2U)) / 2U isn't equal to -((x / 2U) / 2U) for x >= 2. |
| For signed types, even with wrapping overflow, this is fine. */ |
| if (code != MULT_EXPR && TYPE_UNSIGNED (type)) |
| break; |
| if ((t1 = extract_muldiv (op0, c, code, wide_type, strict_overflow_p)) |
| != 0) |
| return fold_build1 (tcode, ctype, fold_convert (ctype, t1)); |
| break; |
| |
| case MIN_EXPR: case MAX_EXPR: |
| /* If widening the type changes the signedness, then we can't perform |
| this optimization as that changes the result. */ |
| if (TYPE_UNSIGNED (ctype) != TYPE_UNSIGNED (type)) |
| break; |
| |
| /* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */ |
| sub_strict_overflow_p = false; |
| if ((t1 = extract_muldiv (op0, c, code, wide_type, |
| &sub_strict_overflow_p)) != 0 |
| && (t2 = extract_muldiv (op1, c, code, wide_type, |
| &sub_strict_overflow_p)) != 0) |
| { |
| if (tree_int_cst_sgn (c) < 0) |
| tcode = (tcode == MIN_EXPR ? MAX_EXPR : MIN_EXPR); |
| if (sub_strict_overflow_p) |
| *strict_overflow_p = true; |
| return fold_build2 (tcode, ctype, fold_convert (ctype, t1), |
| fold_convert (ctype, t2)); |
| } |
| break; |
| |
| case LSHIFT_EXPR: case RSHIFT_EXPR: |
| /* If the second operand is constant, this is a multiplication |
| or floor division, by a power of two, so we can treat it that |
| way unless the multiplier or divisor overflows. Signed |
| left-shift overflow is implementation-defined rather than |
| undefined in C90, so do not convert signed left shift into |
| multiplication. */ |
| if (TREE_CODE (op1) == INTEGER_CST |
| && (tcode == RSHIFT_EXPR || TYPE_UNSIGNED (TREE_TYPE (op0))) |
| /* const_binop may not detect overflow correctly, |
| so check for it explicitly here. */ |
| && wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)), |
| wi::to_wide (op1)) |
| && (t1 = fold_convert (ctype, |
| const_binop (LSHIFT_EXPR, size_one_node, |
| op1))) != 0 |
| && !TREE_OVERFLOW (t1)) |
| return extract_muldiv (build2 (tcode == LSHIFT_EXPR |
| ? MULT_EXPR : FLOOR_DIV_EXPR, |
| ctype, |
| fold_convert (ctype, op0), |
| t1), |
| c, code, wide_type, strict_overflow_p); |
| break; |
| |
| case PLUS_EXPR: case MINUS_EXPR: |
| /* See if we can eliminate the operation on both sides. If we can, we |
| can return a new PLUS or MINUS. If we can't, the only remaining |
| cases where we can do anything are if the second operand is a |
| constant. */ |
| sub_strict_overflow_p = false; |
| t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p); |
| t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p); |
| if (t1 != 0 && t2 != 0 |
| && TYPE_OVERFLOW_WRAPS (ctype) |
| && (code == MULT_EXPR |
| /* If not multiplication, we can only do this if both operands |
| are divisible by c. */ |
| || (multiple_of_p (ctype, op0, c) |
| && multiple_of_p (ctype, op1, c)))) |
| { |
| if (sub_strict_overflow_p) |
| *strict_overflow_p = true; |
| return fold_build2 (tcode, ctype, fold_convert (ctype, t1), |
| fold_convert (ctype, t2)); |
| } |
| |
| /* If this was a subtraction, negate OP1 and set it to be an addition. |
| This simplifies the logic below. */ |
| if (tcode == MINUS_EXPR) |
| { |
| tcode = PLUS_EXPR, op1 = negate_expr (op1); |
| /* If OP1 was not easily negatable, the constant may be OP0. */ |
| if (TREE_CODE (op0) == INTEGER_CST) |
| { |
| std::swap (op0, op1); |
| std::swap (t1, t2); |
| } |
| } |
| |
| if (TREE_CODE (op1) != INTEGER_CST) |
| break; |
| |
| /* If either OP1 or C are negative, this optimization is not safe for |
| some of the division and remainder types while for others we need |
| to change the code. */ |
| if (tree_int_cst_sgn (op1) < 0 || tree_int_cst_sgn (c) < 0) |
| { |
| if (code == CEIL_DIV_EXPR) |
| code = FLOOR_DIV_EXPR; |
| else if (code == FLOOR_DIV_EXPR) |
| code = CEIL_DIV_EXPR; |
| else if (code != MULT_EXPR |
| && code != CEIL_MOD_EXPR && code != FLOOR_MOD_EXPR) |
| break; |
| } |
| |
| /* If it's a multiply or a division/modulus operation of a multiple |
| of our constant, do the operation and verify it doesn't overflow. */ |
| if (code == MULT_EXPR |
| || wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c), |
| TYPE_SIGN (type))) |
| { |
| op1 = const_binop (code, fold_convert (ctype, op1), |
| fold_convert (ctype, c)); |
| /* We allow the constant to overflow with wrapping semantics. */ |
| if (op1 == 0 |
| || (TREE_OVERFLOW (op1) && !TYPE_OVERFLOW_WRAPS (ctype))) |
| break; |
| } |
| else |
| break; |
| |
| /* If we have an unsigned type, we cannot widen the operation since it |
| will change the result if the original computation overflowed. */ |
| if (TYPE_UNSIGNED (ctype) && ctype != type) |
| break; |
| |
| /* The last case is if we are a multiply. In that case, we can |
| apply the distributive law to commute the multiply and addition |
| if the multiplication of the constants doesn't overflow |
| and overflow is defined. With undefined overflow |
| op0 * c might overflow, while (op0 + orig_op1) * c doesn't. |
| But fold_plusminus_mult_expr would factor back any power-of-two |
| value so do not distribute in the first place in this case. */ |
| if (code == MULT_EXPR |
| && TYPE_OVERFLOW_WRAPS (ctype) |
| && !(tree_fits_shwi_p (c) && pow2p_hwi (absu_hwi (tree_to_shwi (c))))) |
| return fold_build2 (tcode, ctype, |
| fold_build2 (code, ctype, |
| fold_convert (ctype, op0), |
| fold_convert (ctype, c)), |
| op1); |
| |
| break; |
| |
| case MULT_EXPR: |
| /* We have a special case here if we are doing something like |
| (C * 8) % 4 since we know that's zero. */ |
| if ((code == TRUNC_MOD_EXPR || code == CEIL_MOD_EXPR |
| || code == FLOOR_MOD_EXPR || code == ROUND_MOD_EXPR) |
| /* If the multiplication can overflow we cannot optimize this. */ |
| && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t)) |
| && TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST |
| && wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c), |
| TYPE_SIGN (type))) |
| { |
| *strict_overflow_p = true; |
| return omit_one_operand (type, integer_zero_node, op0); |
| } |
| |
| /* ... fall through ... */ |
| |
| case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: |
| case ROUND_DIV_EXPR: case EXACT_DIV_EXPR: |
| /* If we can extract our operation from the LHS, do so and return a |
| new operation. Likewise for the RHS from a MULT_EXPR. Otherwise, |
| do something only if the second operand is a constant. */ |
| if (same_p |
| && TYPE_OVERFLOW_WRAPS (ctype) |
| && (t1 = extract_muldiv (op0, c, code, wide_type, |
| strict_overflow_p)) != 0) |
| return fold_build2 (tcode, ctype, fold_convert (ctype, t1), |
| fold_convert (ctype, op1)); |
| else if (tcode == MULT_EXPR && code == MULT_EXPR |
| && TYPE_OVERFLOW_WRAPS (ctype) |
| && (t1 = extract_muldiv (op1, c, code, wide_type, |
| strict_overflow_p)) != 0) |
| return fold_build2 (tcode, ctype, fold_convert (ctype, op0), |
| fold_convert (ctype, t1)); |
| else if (TREE_CODE (op1) != INTEGER_CST) |
| return 0; |
| |
| /* If these are the same operation types, we can associate them |
| assuming no overflow. */ |
| if (tcode == code) |
| { |
| bool overflow_p = false; |
| wi::overflow_type overflow_mul; |
| signop sign = TYPE_SIGN (ctype); |
| unsigned prec = TYPE_PRECISION (ctype); |
| wide_int mul = wi::mul (wi::to_wide (op1, prec), |
| wi::to_wide (c, prec), |
| sign, &overflow_mul); |
| overflow_p = TREE_OVERFLOW (c) | TREE_OVERFLOW (op1); |
| if (overflow_mul |
| && ((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)); |
| } |
| |
| /* If these operations "cancel" each other, we have the main |
| optimizations of this pass, which occur when either constant is a |
| multiple of the other, in which case we replace this with either an |
| operation or CODE or TCODE. |
| |
| If we have an unsigned type, we cannot do this since it will change |
| the result if the original computation overflowed. */ |
| if (TYPE_OVERFLOW_UNDEFINED (ctype) |
| && ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR) |
| || (tcode == MULT_EXPR |
| && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR |
| && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR |
| && code != MULT_EXPR))) |
| { |
| if (wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c), |
| TYPE_SIGN (type))) |
| { |
| if (TYPE_OVERFLOW_UNDEFINED (ctype)) |
| *strict_overflow_p = true; |
| return fold_build2 (tcode, ctype, fold_convert (ctype, op0), |
| fold_convert (ctype, |
| const_binop (TRUNC_DIV_EXPR, |
| op1, c))); |
| } |
| else if (wi::multiple_of_p (wi::to_wide (c), wi::to_wide (op1), |
| TYPE_SIGN (type))) |
| { |
| if (TYPE_OVERFLOW_UNDEFINED (ctype)) |
| *strict_overflow_p = true; |
| return fold_build2 (code, ctype, fold_convert (ctype, op0), |
| fold_convert (ctype, |
| const_binop (TRUNC_DIV_EXPR, |
| c, op1))); |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| /* Return a node which has the indicated constant VALUE (either 0 or |
| 1 for scalars or {-1,-1,..} or {0,0,...} for vectors), |
| and is of the indicated TYPE. */ |
| |
| tree |
| constant_boolean_node (bool value, tree type) |
| { |
| if (type == integer_type_node) |
| return value ? integer_one_node : integer_zero_node; |
| else if (type == boolean_type_node) |
| return value ? boolean_true_node : boolean_false_node; |
| else if (TREE_CODE (type) == VECTOR_TYPE) |
| return build_vector_from_val (type, |
| build_int_cst (TREE_TYPE (type), |
| value ? -1 : 0)); |
| else |
| return fold_convert (type, value ? integer_one_node : integer_zero_node); |
| } |
| |
| |
| /* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'. |
| Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'. Here |
| CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)' |
| expression, and ARG to `a'. If COND_FIRST_P is nonzero, then the |
| COND is the first argument to CODE; otherwise (as in the example |
| given here), it is the second argument. TYPE is the type of the |
| original expression. Return NULL_TREE if no simplification is |
| possible. */ |
| |
| static tree |
| fold_binary_op_with_conditional_arg (location_t loc, |
| enum tree_code code, |
| tree type, tree op0, tree op1, |
| tree cond, tree arg, int cond_first_p) |
| { |
| tree cond_type = cond_first_p ? TREE_TYPE (op0) : TREE_TYPE (op1); |
| tree arg_type = cond_first_p ? TREE_TYPE (op1) : TREE_TYPE (op0); |
| tree test, true_value, false_value; |
| tree lhs = NULL_TREE; |
| tree rhs = NULL_TREE; |
| enum tree_code cond_code = COND_EXPR; |
| |
| /* Do not move possibly trapping operations into the conditional as this |
| pessimizes code and causes gimplification issues when applied late. */ |
| if (operation_could_trap_p (code, FLOAT_TYPE_P (type), |
| ANY_INTEGRAL_TYPE_P (type) |
| && TYPE_OVERFLOW_TRAPS (type), op1)) |
| return NULL_TREE; |
| |
| if (TREE_CODE (cond) == COND_EXPR |
| || TREE_CODE (cond) == VEC_COND_EXPR) |
| { |
| test = TREE_OPERAND (cond, 0); |
| true_value = TREE_OPERAND (cond, 1); |
| false_value = TREE_OPERAND (cond, 2); |
| /* If this operand throws an expression, then it does not make |
| sense to try to perform a logical or arithmetic operation |
| involving it. */ |
| if (VOID_TYPE_P (TREE_TYPE (true_value))) |
| lhs = true_value; |
| if (VOID_TYPE_P (TREE_TYPE (false_value))) |
| rhs = false_value; |
| } |
| else if (!(TREE_CODE (type) != VECTOR_TYPE |
| && TREE_CODE (TREE_TYPE (cond)) == VECTOR_TYPE)) |
| { |
| tree testtype = TREE_TYPE (cond); |
| test = cond; |
| true_value = constant_boolean_node (true, testtype); |
| false_value = constant_boolean_node (false, testtype); |
| } |
| else |
| /* Detect the case of mixing vector and scalar types - bail out. */ |
| return NULL_TREE; |
| |
| if (TREE_CODE (TREE_TYPE (test)) == VECTOR_TYPE) |
| cond_code = VEC_COND_EXPR; |
| |
| /* This transformation is only worthwhile if we don't have to wrap ARG |
| in a SAVE_EXPR and the operation can be simplified without recursing |
| on at least one of the branches once its pushed inside the COND_EXPR. */ |
| if (!TREE_CONSTANT (arg) |
| && (TREE_SIDE_EFFECTS (arg) |
| || TREE_CODE (arg) == COND_EXPR || TREE_CODE (arg) == VEC_COND_EXPR |
| || TREE_CONSTANT (true_value) || TREE_CONSTANT (false_value))) |
| return NULL_TREE; |
| |
| arg = fold_convert_loc (loc, arg_type, arg); |
| if (lhs == 0) |
| { |
| true_value = fold_convert_loc (loc, cond_type, true_value); |
| if (cond_first_p) |
| lhs = fold_build2_loc (loc, code, type, true_value, arg); |
| else |
| lhs = fold_build2_loc (loc, code, type, arg, true_value); |
| } |
| if (rhs == 0) |
| { |
| false_value = fold_convert_loc (loc, cond_type, false_value); |
| if (cond_first_p) |
| rhs = fold_build2_loc (loc, code, type, false_value, arg); |
| else |
| rhs = fold_build2_loc (loc, code, type, arg, false_value); |
| } |
| |
| /* Check that we have simplified at least one of the branches. */ |
| if (!TREE_CONSTANT (arg) && !TREE_CONSTANT (lhs) && !TREE_CONSTANT (rhs)) |
| return NULL_TREE; |
| |
| return fold_build3_loc (loc, cond_code, type, test, lhs, rhs); |
| } |
| |
| |
| /* Subroutine of fold() that checks for the addition of ARG +/- 0.0. |
| |
| If !NEGATE, return true if ZERO_ARG is +/-0.0 and, for all ARG of |
| type TYPE, ARG + ZERO_ARG is the same as ARG. If NEGATE, return true |
| if ARG - ZERO_ARG is the same as X. |
| |
| If ARG is NULL, check for any value of type TYPE. |
| |
| X + 0 and X - 0 both give X when X is NaN, infinite, or nonzero |
| and finite. The problematic cases are when X is zero, and its mode |
| has signed zeros. In the case of rounding towards -infinity, |
| X - 0 is not the same as X because 0 - 0 is -0. In other rounding |
| modes, X + 0 is not the same as X because -0 + 0 is 0. */ |
| |
| bool |
| fold_real_zero_addition_p (const_tree type, const_tree arg, |
| const_tree zero_arg, int negate) |
| { |
| if (!real_zerop (zero_arg)) |
| return false; |
| |
| /* Don't allow the fold with -fsignaling-nans. */ |
| if (arg ? tree_expr_maybe_signaling_nan_p (arg) : HONOR_SNANS (type)) |
| return false; |
| |
| /* Allow the fold if zeros aren't signed, or their sign isn't important. */ |
| if (!HONOR_SIGNED_ZEROS (type)) |
| return true; |
| |
| /* There is no case that is safe for all rounding modes. */ |
| if (HONOR_SIGN_DEPENDENT_ROUNDING (type)) |
| return false; |
| |
| /* In a vector or complex, we would need to check the sign of all zeros. */ |
| if (TREE_CODE (zero_arg) == VECTOR_CST) |
| zero_arg = uniform_vector_p (zero_arg); |
| if (!zero_arg || TREE_CODE (zero_arg) != REAL_CST) |
| return false; |
| |
| /* Treat x + -0 as x - 0 and x - -0 as x + 0. */ |
| if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (zero_arg))) |
| negate = !negate; |
| |
| /* The mode has signed zeros, and we have to honor their sign. |
| In this situation, there are only two cases we can return true for. |
| (i) X - 0 is the same as X with default rounding. |
| (ii) X + 0 is X when X can't possibly be -0.0. */ |
| return negate || (arg && !tree_expr_maybe_real_minus_zero_p (arg)); |
| } |
| |
| /* Subroutine of match.pd that optimizes comparisons of a division by |
| a nonzero integer constant against an integer constant, i.e. |
| X/C1 op C2. |
| |
| CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, |
| GE_EXPR or LE_EXPR. ARG01 and ARG1 must be a INTEGER_CST. */ |
| |
| enum tree_code |
| fold_div_compare (enum tree_code code, tree c1, tree c2, tree *lo, |
| tree *hi, bool *neg_overflow) |
| { |
| tree prod, tmp, type = TREE_TYPE (c1); |
| signop sign = TYPE_SIGN (type); |
| wi::overflow_type overflow; |
| |
| /* We have to do this the hard way to detect unsigned overflow. |
| prod = int_const_binop (MULT_EXPR, c1, c2); */ |
| wide_int val = wi::mul (wi::to_wide (c1), wi::to_wide (c2), sign, &overflow); |
| prod = force_fit_type (type, val, -1, overflow); |
| *neg_overflow = false; |
| |
| if (sign == UNSIGNED) |
| { |
| tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1)); |
| *lo = prod; |
| |
| /* Likewise *hi = int_const_binop (PLUS_EXPR, prod, tmp). */ |
| val = wi::add (wi::to_wide (prod), wi::to_wide (tmp), sign, &overflow); |
| *hi = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (prod)); |
| } |
| else if (tree_int_cst_sgn (c1) >= 0) |
| { |
| tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1)); |
| switch (tree_int_cst_sgn (c2)) |
| { |
| case -1: |
| *neg_overflow = true; |
| *lo = int_const_binop (MINUS_EXPR, prod, tmp); |
| *hi = prod; |
| break; |
| |
| case 0: |
| *lo = fold_negate_const (tmp, type); |
| *hi = tmp; |
| break; |
| |
| case 1: |
| *hi = int_const_binop (PLUS_EXPR, prod, tmp); |
| *lo = prod; |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| else |
| { |
| /* A negative divisor reverses the relational operators. */ |
| code = swap_tree_comparison (code); |
| |
| tmp = int_const_binop (PLUS_EXPR, c1, build_int_cst (type, 1)); |
| switch (tree_int_cst_sgn (c2)) |
| { |
| case -1: |
| *hi = int_const_binop (MINUS_EXPR, prod, tmp); |
| *lo = prod; |
| break; |
| |
| case 0: |
| *hi = fold_negate_const (tmp, type); |
| *lo = tmp; |
| break; |
| |
| case 1: |
| *neg_overflow = true; |
| *lo = int_const_binop (PLUS_EXPR, prod, tmp); |
| *hi = prod; |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| if (code != EQ_EXPR && code != NE_EXPR) |
| return code; |
| |
| if (TREE_OVERFLOW (*lo) |
| || operand_equal_p (*lo, TYPE_MIN_VALUE (type), 0)) |
| *lo = NULL_TREE; |
| if (TREE_OVERFLOW (*hi) |
| || operand_equal_p (*hi, TYPE_MAX_VALUE (type), 0)) |
| *hi = NULL_TREE; |
| |
| return code; |
| } |
| |
| |
| /* If CODE with arguments ARG0 and ARG1 represents a single bit |
| equality/inequality test, then return a simplified form of the test |
| using a sign testing. Otherwise return NULL. TYPE is the desired |
| result type. */ |
| |
| static tree |
| fold_single_bit_test_into_sign_test (location_t loc, |
| enum tree_code code, tree arg0, tree arg1, |
| tree result_type) |
| { |
| /* If this is testing a single bit, we can optimize the test. */ |
| if ((code == NE_EXPR || code == EQ_EXPR) |
| && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) |
| && integer_pow2p (TREE_OPERAND (arg0, 1))) |
| { |
| /* If we have (A & C) != 0 where C is the sign bit of A, convert |
| this into A < 0. Similarly for (A & C) == 0 into A >= 0. */ |
| tree arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)); |
| |
| if (arg00 != NULL_TREE |
| /* This is only a win if casting to a signed type is cheap, |
| i.e. when arg00's type is not a partial mode. */ |
| && type_has_mode_precision_p (TREE_TYPE (arg00))) |
| { |
| tree stype = signed_type_for (TREE_TYPE (arg00)); |
| return fold_build2_loc (loc, code == EQ_EXPR ? GE_EXPR : LT_EXPR, |
| result_type, |
| fold_convert_loc (loc, stype, arg00), |
| build_int_cst (stype, 0)); |
| } |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* If CODE with arguments ARG0 and ARG1 represents a single bit |
| equality/inequality test, then return a simplified form of |
| the test using shifts and logical operations. Otherwise return |
| NULL. TYPE is the desired result type. */ |
| |
| tree |
| fold_single_bit_test (location_t loc, enum tree_code code, |
| tree arg0, tree arg1, tree result_type) |
| { |
| /* If this is testing a single bit, we can optimize the test. */ |
| if ((code == NE_EXPR || code == EQ_EXPR) |
| && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) |
| && integer_pow2p (TREE_OPERAND (arg0, 1))) |
| { |
| tree inner = TREE_OPERAND (arg0, 0); |
| tree type = TREE_TYPE (arg0); |
| int bitnum = tree_log2 (TREE_OPERAND (arg0, 1)); |
| scalar_int_mode operand_mode = SCALAR_INT_TYPE_MODE (type); |
| int ops_unsigned; |
| tree signed_type, unsigned_type, intermediate_type; |
| tree tem, one; |
| |
| /* First, see if we can fold the single bit test into a sign-bit |
| test. */ |
| tem = fold_single_bit_test_into_sign_test (loc, code, arg0, arg1, |
| result_type); |
| if (tem) |
| return tem; |
| |
| /* Otherwise we have (A & C) != 0 where C is a single bit, |
| convert that into ((A >> C2) & 1). Where C2 = log2(C). |
| Similarly for (A & C) == 0. */ |
| |
| /* If INNER is a right shift of a constant and it plus BITNUM does |
| not overflow, adjust BITNUM and INNER. */ |
| if (TREE_CODE (inner) == RSHIFT_EXPR |
| && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST |
| && bitnum < TYPE_PRECISION (type) |
| && wi::ltu_p (wi::to_wide (TREE_OPERAND (inner, 1)), |
| TYPE_PRECISION (type) - bitnum)) |
| { |
| bitnum += tree_to_uhwi (TREE_OPERAND (inner, 1)); |
| inner = TREE_OPERAND (inner, 0); |
| } |
| |
| /* 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. */ |
| ops_unsigned = (load_extend_op (operand_mode) == SIGN_EXTEND |
| && !flag_syntax_only) ? 0 : 1; |
| |
| signed_type = lang_hooks.types.type_for_mode (operand_mode, 0); |
| unsigned_type = lang_hooks.types.type_for_mode (operand_mode, 1); |
| intermediate_type = ops_unsigned ? unsigned_type : signed_type; |
| inner = fold_convert_loc (loc, intermediate_type, inner); |
| |
| if (bitnum != 0) |
| inner = build2 (RSHIFT_EXPR, intermediate_type, |
| inner, size_int (bitnum)); |
| |
| one = build_int_cst (intermediate_type, 1); |
| |
| if (code == EQ_EXPR) |
| inner = fold_build2_loc (loc, BIT_XOR_EXPR, intermediate_type, inner, one); |
| |
| /* Put the AND last so it can combine with more things. */ |
| inner = build2 (BIT_AND_EXPR, intermediate_type, inner, one); |
| |
| /* Make sure to return the proper type. */ |
| inner = fold_convert_loc (loc, result_type, inner); |
| |
| return inner; |
| } |
| return NULL_TREE; |
| } |
| |
| /* Test whether it is preferable to swap two operands, ARG0 and |
| ARG1, for example because ARG0 is an integer constant and ARG1 |
| isn't. */ |
| |
| bool |
| tree_swap_operands_p (const_tree arg0, const_tree arg1) |
| { |
| if (CONSTANT_CLASS_P (arg1)) |
| return 0; |
| if (CONSTANT_CLASS_P (arg0)) |
| return 1; |
| |
| STRIP_NOPS (arg0); |
| STRIP_NOPS (arg1); |
| |
| if (TREE_CONSTANT (arg1)) |
| return 0; |
| if (TREE_CONSTANT (arg0)) |
| return 1; |
| |
| /* It is preferable to swap two SSA_NAME to ensure a canonical form |
| for commutative and comparison operators. Ensuring a canonical |
| form allows the optimizers to find additional redundancies without |
| having to explicitly check for both orderings. */ |
| if (TREE_CODE (arg0) == SSA_NAME |
| && TREE_CODE (arg1) == SSA_NAME |
| && SSA_NAME_VERSION (arg0) > SSA_NAME_VERSION (arg1)) |
| return 1; |
| |
| /* Put SSA_NAMEs last. */ |
| if (TREE_CODE (arg1) == SSA_NAME) |
| return 0; |
| if (TREE_CODE (arg0) == SSA_NAME) |
| return 1; |
| |
| /* Put variables last. */ |
| if (DECL_P (arg1)) |
| return 0; |
| if (DECL_P (arg0)) |
| return 1; |
| |
| return 0; |
| } |
| |
| |
| /* 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 |
| A < X <= MAX. INEQ is A + 1 > Y, BOUND is A < X. */ |
| |
| static tree |
| fold_to_nonsharp_ineq_using_bound (location_t loc, tree ineq, tree bound) |
| { |
| tree a, typea, type = TREE_TYPE (ineq), a1, diff, y; |
| |
| if (TREE_CODE (bound) == LT_EXPR) |
| a = TREE_OPERAND (bound, 0); |
| else if (TREE_CODE (bound) == GT_EXPR) |
| a = TREE_OPERAND (bound, 1); |
| else |
| return NULL_TREE; |
| |
| typea = TREE_TYPE (a); |
| if (!INTEGRAL_TYPE_P (typea) |
| && !POINTER_TYPE_P (typea)) |
| return NULL_TREE; |
| |
| if (TREE_CODE (ineq) == LT_EXPR) |
| { |
| a1 = TREE_OPERAND (ineq, 1); |
| y = TREE_OPERAND (ineq, 0); |
| } |
| else if (TREE_CODE (ineq) == GT_EXPR) |
| { |
| a1 = TREE_OPERAND (ineq, 0); |
| y = TREE_OPERAND (ineq, 1); |
| } |
| else |
| return NULL_TREE; |
| |
| if (TREE_TYPE (a1) != typea) |
| return NULL_TREE; |
| |
| if (POINTER_TYPE_P (typea)) |
| { |
| /* Convert the pointer types into integer before taking the difference. */ |
| tree ta = fold_convert_loc (loc, ssizetype, a); |
| tree ta1 = fold_convert_loc (loc, ssizetype, a1); |
| diff = fold_binary_loc (loc, MINUS_EXPR, ssizetype, ta1, ta); |
| } |
| else |
| diff = fold_binary_loc (loc, MINUS_EXPR, typea, a1, a); |
| |
| if (!diff || !integer_onep (diff)) |
| return NULL_TREE; |
| |
| return fold_build2_loc (loc, GE_EXPR, type, a, y); |
| } |
| |
| /* Fold a sum or difference of at least one multiplication. |
| Returns the folded tree or NULL if no simplification could be made. */ |
| |
| static tree |
| fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type, |
| tree arg0, tree arg1) |
| { |
| tree arg00, arg01, arg10, arg11; |
| tree alt0 = NULL_TREE, alt1 = NULL_TREE, same; |
| |
| /* (A * C) +- (B * C) -> (A+-B) * C. |
| (A * C) +- A -> A * (C+-1). |
| We are most concerned about the case where C is a constant, |
| but other combinations show up during loop reduction. Since |
| it is not difficult, try all four possibilities. */ |
| |
| if (TREE_CODE (arg0) == MULT_EXPR) |
| { |
| arg00 = TREE_OPERAND (arg0, 0); |
| arg01 = TREE_OPERAND (arg0, 1); |
| } |
| else if (TREE_CODE (arg0) == INTEGER_CST) |
| { |
| arg00 = build_one_cst (type); |
| arg01 = arg0; |
| } |
| else |
| { |
| /* We cannot generate constant 1 for fract. */ |
| if (ALL_FRACT_MODE_P (TYPE_MODE (type))) |
| return NULL_TREE; |
| arg00 = arg0; |
| arg01 = build_one_cst (type); |
| } |
| if (TREE_CODE (arg1) == MULT_EXPR) |
| { |
| arg10 = TREE_OPERAND (arg1, 0); |
| arg11 = TREE_OPERAND (arg1, 1); |
| } |
| else if (TREE_CODE (arg1) == INTEGER_CST) |
| { |
| arg10 = build_one_cst (type); |
| /* As we canonicalize A - 2 to A + -2 get rid of that sign for |
| the purpose of this canonicalization. */ |
| if (wi::neg_p (wi::to_wide (arg1), TYPE_SIGN (TREE_TYPE (arg1))) |
| && negate_expr_p (arg1) |
| && code == PLUS_EXPR) |
| { |
| arg11 = negate_expr (arg1); |
| code = MINUS_EXPR; |
| } |
| else |
| arg11 = arg1; |
| } |
| else |
| { |
| /* We cannot generate constant 1 for fract. */ |
| if (ALL_FRACT_MODE_P (TYPE_MODE (type))) |
| return NULL_TREE; |
| arg10 = arg1; |
| arg11 = build_one_cst (type); |
| } |
| same = NULL_TREE; |
| |
| /* Prefer factoring a common non-constant. */ |
| if (operand_equal_p (arg00, arg10, 0)) |
| same = arg00, alt0 = arg01, alt1 = arg11; |
| else if (operand_equal_p (arg01, arg11, 0)) |
| same = arg01, alt0 = arg00, alt1 = arg10; |
| else if (operand_equal_p (arg00, arg11, 0)) |
| same = arg00, alt0 = arg01, alt1 = arg10; |
| else if (operand_equal_p (arg01, arg10, 0)) |
| same = arg01, alt0 = arg00, alt1 = arg11; |
| |
| /* No identical multiplicands; see if we can find a common |
| power-of-two factor in non-power-of-two multiplies. This |
| can help in multi-dimensional array access. */ |
| else if (tree_fits_shwi_p (arg01) && tree_fits_shwi_p (arg11)) |
| { |
| HOST_WIDE_INT int01 = tree_to_shwi (arg01); |
| HOST_WIDE_INT int11 = tree_to_shwi (arg11); |
| HOST_WIDE_INT tmp; |
| bool swap = false; |
| tree maybe_same; |
| |
| /* Move min of absolute values to int11. */ |
| if (absu_hwi (int01) < absu_hwi (int11)) |
| { |
| tmp = int01, int01 = int11, int11 = tmp; |
| alt0 = arg00, arg00 = arg10, arg10 = alt0; |
| maybe_same = arg01; |
| swap = true; |
| } |
| else |
| maybe_same = arg11; |
| |
| const unsigned HOST_WIDE_INT factor = absu_hwi (int11); |
| if (factor > 1 |
| && pow2p_hwi (factor) |
| && (int01 & (factor - 1)) == 0 |
| /* The remainder should not be a constant, otherwise we |
| end up folding i * 4 + 2 to (i * 2 + 1) * 2 which has |
| increased the number of multiplications necessary. */ |
| && TREE_CODE (arg10) != INTEGER_CST) |
| { |
| alt0 = fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (arg00), arg00, |
| build_int_cst (TREE_TYPE (arg00), |
| int01 / int11)); |
| alt1 = arg10; |
| same = maybe_same; |
| if (swap) |
| maybe_same = alt0, alt0 = alt1, alt1 = maybe_same; |
| } |
| } |
| |
| if (!same) |
| return NULL_TREE; |
| |
| if (! ANY_INTEGRAL_TYPE_P (type) |
| || TYPE_OVERFLOW_WRAPS (type) |
| /* We are neither factoring zero nor minus one. */ |
| || TREE_CODE (same) == INTEGER_CST) |
| return fold_build2_loc (loc, MULT_EXPR, type, |
| fold_build2_loc (loc, code, type, |
| fold_convert_loc (loc, type, alt0), |
| fold_convert_loc (loc, type, alt1)), |
| fold_convert_loc (loc, type, same)); |
| |
| /* Same may be zero and thus the operation 'code' may overflow. Likewise |
| same may be minus one and thus the multiplication may overflow. Perform |
| the sum operation in an unsigned type. */ |
| tree utype = unsigned_type_for (type); |
| tree tem = fold_build2_loc (loc, code, utype, |
| fold_convert_loc (loc, utype, alt0), |
| fold_convert_loc (loc, utype, alt1)); |
| /* If the sum evaluated to a constant that is not -INF the multiplication |
| cannot overflow. */ |
| if (TREE_CODE (tem) == INTEGER_CST |
| && (wi::to_wide (tem) |
| != wi::min_value (TYPE_PRECISION (utype), SIGNED))) |
| return fold_build2_loc (loc, MULT_EXPR, type, |
| fold_convert (type, tem), same); |
| |
| /* Do not resort to unsigned multiplication because |
| we lose the no-overflow property of the expression. */ |
| return NULL_TREE; |
| } |
| |
| /* Subroutine of native_encode_expr. Encode the INTEGER_CST |
| specified by EXPR into the buffer PTR of length LEN bytes. |
| Return the number of bytes placed in the buffer, or zero |
| upon failure. */ |
| |
| static int |
| native_encode_int (const_tree expr, unsigned char *ptr, int len, int off) |
| { |
| tree type = TREE_TYPE (expr); |
| int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)); |
| int byte, offset, word, words; |
| unsigned char value; |
| |
| if ((off == -1 && total_bytes > len) || off >= total_bytes) |
| return 0; |
| if (off == -1) |
| off = 0; |
| |
| if (ptr == NULL) |
| /* Dry run. */ |
| return MIN (len, total_bytes - off); |
| |
| words = total_bytes / UNITS_PER_WORD; |
| |
| for (byte = 0; byte < total_bytes; byte++) |
| { |
| int bitpos = byte * BITS_PER_UNIT; |
| /* Extend EXPR according to TYPE_SIGN if the precision isn't a whole |
| number of bytes. */ |
| value = wi::extract_uhwi (wi::to_widest (expr), bitpos, BITS_PER_UNIT); |
| |
| if (total_bytes > UNITS_PER_WORD) |
| { |
| word = byte / UNITS_PER_WORD; |
| if (WORDS_BIG_ENDIAN) |
| word = (words - 1) - word; |
| offset = word * UNITS_PER_WORD; |
| if (BYTES_BIG_ENDIAN) |
| offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); |
| else |
| offset += byte % UNITS_PER_WORD; |
| } |
| else |
| offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte; |
| if (offset >= off && offset - off < len) |
| ptr[offset - off] = value; |
| } |
| return MIN (len, total_bytes - off); |
| } |
| |
| |
| /* Subroutine of native_encode_expr. Encode the FIXED_CST |
| specified by EXPR into the buffer PTR of length LEN bytes. |
| Return the number of bytes placed in the buffer, or zero |
| upon failure. */ |
| |
| static int |
| native_encode_fixed (const_tree expr, unsigned char *ptr, int len, int off) |
| { |
| tree type = TREE_TYPE (expr); |
| scalar_mode mode = SCALAR_TYPE_MODE (type); |
| int total_bytes = GET_MODE_SIZE (mode); |
| FIXED_VALUE_TYPE value; |
| tree i_value, i_type; |
| |
| if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) |
| return 0; |
| |
| i_type = lang_hooks.types.type_for_size (GET_MODE_BITSIZE (mode), 1); |
| |
| if (NULL_TREE == i_type || TYPE_PRECISION (i_type) != total_bytes) |
| return 0; |
| |
| value = TREE_FIXED_CST (expr); |
| i_value = double_int_to_tree (i_type, value.data); |
| |
| return native_encode_int (i_value, ptr, len, off); |
| } |
| |
| |
| /* Subroutine of native_encode_expr. Encode the REAL_CST |
| specified by EXPR into the buffer PTR of length LEN bytes. |
| Return the number of bytes placed in the buffer, or zero |
| upon failure. */ |
| |
| static int |
| native_encode_real (const_tree expr, unsigned char *ptr, int len, int off) |
| { |
| tree type = TREE_TYPE (expr); |
| int total_bytes = GET_MODE_SIZE (SCALAR_FLOAT_TYPE_MODE (type)); |
| 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 |
| up to 192 bits. */ |
| long tmp[6]; |
| |
| if ((off == -1 && total_bytes > len) || off >= total_bytes) |
| return 0; |
| if (off == -1) |
| off = 0; |
| |
| if (ptr == NULL) |
| /* Dry run. */ |
| return MIN (len, total_bytes - off); |
| |
| words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD; |
| |
| real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type)); |
| |
| for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT; |
| bitpos += BITS_PER_UNIT) |
| { |
| byte = (bitpos / BITS_PER_UNIT) & 3; |
| value = (unsigned char) (tmp[bitpos / 32] >> (bitpos & 31)); |
| |
| if (UNITS_PER_WORD < 4) |
| { |
| word = byte / UNITS_PER_WORD; |
| if (WORDS_BIG_ENDIAN) |
| word = (words - 1) - word; |
| offset = word * UNITS_PER_WORD; |
| if (BYTES_BIG_ENDIAN) |
| offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); |
| else |
| offset += byte % UNITS_PER_WORD; |
| } |
| else |
| { |
| 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); |
| } |
| } |
| offset = offset + ((bitpos / BITS_PER_UNIT) & ~3); |
| if (offset >= off |
| && offset - off < len) |
| ptr[offset - off] = value; |
| } |
| return MIN (len, total_bytes - off); |
| } |
| |
| /* Subroutine of native_encode_expr. Encode the COMPLEX_CST |
| specified by EXPR into the buffer PTR of length LEN bytes. |
| Return the number of bytes placed in the buffer, or zero |
| upon failure. */ |
| |
| static int |
| native_encode_complex (const_tree expr, unsigned char *ptr, int len, int off) |
| { |
| int rsize, isize; |
| tree part; |
| |
| part = TREE_REALPART (expr); |
| rsize = native_encode_expr (part, ptr, len, off); |
| if (off == -1 && rsize == 0) |
| return 0; |
| part = TREE_IMAGPART (expr); |
| if (off != -1) |
| off = MAX (0, off - GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (part)))); |
| isize = native_encode_expr (part, ptr ? ptr + rsize : NULL, |
| len - rsize, off); |
| if (off == -1 && isize != rsize) |
| return 0; |
| return rsize + isize; |
| } |
| |
| /* Like native_encode_vector, but only encode the first COUNT elements. |
| The other arguments are as for native_encode_vector. */ |
| |
| static int |
| native_encode_vector_part (const_tree expr, unsigned char *ptr, int len, |
| int off, unsigned HOST_WIDE_INT count) |
| { |
| tree itype = TREE_TYPE (TREE_TYPE (expr)); |
| if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (expr)) |
| && TYPE_PRECISION (itype) <= BITS_PER_UNIT) |
| { |
| /* This is the only case in which elements can be smaller than a byte. |
| Element 0 is always in the lsb of the containing byte. */ |
| unsigned int elt_bits = TYPE_PRECISION (itype); |
| int total_bytes = CEIL (elt_bits * count, BITS_PER_UNIT); |
| if ((off == -1 && total_bytes > len) || off >= total_bytes) |
| return 0; |
| |
| if (off == -1) |
| off = 0; |
| |
| /* Zero the buffer and then set bits later where necessary. */ |
| int extract_bytes = MIN (len, total_bytes - off); |
| if (ptr) |
| memset (ptr, 0, extract_bytes); |
| |
| unsigned int elts_per_byte = BITS_PER_UNIT / elt_bits; |
| unsigned int first_elt = off * elts_per_byte; |
| unsigned int extract_elts = extract_bytes * elts_per_byte; |
| for (unsigned int i = 0; i < extract_elts; ++i) |
| { |
| tree elt = VECTOR_CST_ELT (expr, first_elt + i); |
| if (TREE_CODE (elt) != INTEGER_CST) |
| return 0; |
| |
| if (ptr && wi::extract_uhwi (wi::to_wide (elt), 0, 1)) |
| { |
| unsigned int bit = i * elt_bits; |
| ptr[bit / BITS_PER_UNIT] |= 1 << (bit % BITS_PER_UNIT); |
| } |
| } |
| return extract_bytes; |
| } |
| |
| int offset = 0; |
| int size = GET_MODE_SIZE (SCALAR_TYPE_MODE (itype)); |
| for (unsigned HOST_WIDE_INT i = 0; i < count; i++) |
| { |
| if (off >= size) |
| { |
| off -= size; |
| continue; |
| } |
| tree elem = VECTOR_CST_ELT (expr, i); |
| int res = native_encode_expr (elem, ptr ? ptr + offset : NULL, |
| len - offset, off); |
| if ((off == -1 && res != size) || res == 0) |
| return 0; |
| offset += res; |
| if (offset >= len) |
| return (off == -1 && i < count - 1) ? 0 : offset; |
| if (off != -1) |
| off = 0; |
| } |
| return offset; |
| } |
| |
| /* Subroutine of native_encode_expr. Encode the VECTOR_CST |
| specified by EXPR into the buffer PTR of length LEN bytes. |
| Return the number of bytes placed in the buffer, or zero |
| upon failure. */ |
| |
| static int |
| native_encode_vector (const_tree expr, unsigned char *ptr, int len, int off) |
| { |
| unsigned HOST_WIDE_INT count; |
| if (!VECTOR_CST_NELTS (expr).is_constant (&count)) |
| return 0; |
| return native_encode_vector_part (expr, ptr, len, off, count); |
| } |
| |
| |
| /* Subroutine of native_encode_expr. Encode the STRING_CST |
| specified by EXPR into the buffer PTR of length LEN bytes. |
| Return the number of bytes placed in the buffer, or zero |
| upon failure. */ |
| |
| static int |
| native_encode_string (const_tree expr, unsigned char *ptr, int len, int off) |
| { |
| tree type = TREE_TYPE (expr); |
| |
| /* Wide-char strings are encoded in target byte-order so native |
| encoding them is trivial. */ |
| if (BITS_PER_UNIT != CHAR_BIT |
| || TREE_CODE (type) != ARRAY_TYPE |
| || TREE_CODE (TREE_TYPE (type)) != INTEGER_TYPE |
| || !tree_fits_shwi_p (TYPE_SIZE_UNIT (type))) |
| return 0; |
| |
| HOST_WIDE_INT total_bytes = tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (expr))); |
| if ((off == -1 && total_bytes > len) || off >= total_bytes) |
| return 0; |
| if (off == -1) |
| off = 0; |
| len = MIN (total_bytes - off, len); |
| if (ptr == NULL) |
| /* Dry run. */; |
| else |
| { |
| int written = 0; |
| if (off < TREE_STRING_LENGTH (expr)) |
| { |
| written = MIN (len, TREE_STRING_LENGTH (expr) - off); |
| memcpy (ptr, TREE_STRING_POINTER (expr) + off, written); |
| } |
| memset (ptr + written, 0, len - written); |
| } |
| return len; |
| } |
| |
| |
| /* Subroutine of fold_view_convert_expr. Encode the INTEGER_CST, REAL_CST, |
| FIXED_CST, COMPLEX_CST, STRING_CST, or VECTOR_CST specified by EXPR into |
| the buffer PTR of size LEN bytes. If PTR is NULL, don't actually store |
| anything, just do a dry run. Fail either if OFF is -1 and LEN isn't |
| sufficient to encode the entire EXPR, or if OFF is out of bounds. |
| Otherwise, start at byte offset OFF and encode at most LEN bytes. |
| Return the number of bytes placed in the buffer, or zero upon failure. */ |
| |
| 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: |
| return native_encode_int (expr, ptr, len, off); |
| |
| case REAL_CST: |
| return native_encode_real (expr, ptr, len, off); |
| |
| case FIXED_CST: |
| return native_encode_fixed (expr, ptr, len, off); |
| |
| case COMPLEX_CST: |
| return native_encode_complex (expr, ptr, len, off); |
| |
| case VECTOR_CST: |
| return native_encode_vector (expr, ptr, len, off); |
| |
| case STRING_CST: |
| return native_encode_string (expr, ptr, len, off); |
| |
| default: |
| return 0; |
| } |
| } |
| |
| /* Try to find a type whose byte size is smaller or equal to LEN bytes larger |
| or equal to FIELDSIZE bytes, with underlying mode precision/size multiple |
| of BITS_PER_UNIT. As native_{interpret,encode}_int works in term of |
| machine modes, we can't just use build_nonstandard_integer_type. */ |
| |
| tree |
| find_bitfield_repr_type (int fieldsize, int len) |
| { |
| machine_mode mode; |
| for (int pass = 0; pass < 2; pass++) |
| { |
| enum mode_class mclass = pass ? MODE_PARTIAL_INT : MODE_INT; |
| FOR_EACH_MODE_IN_CLASS (mode, mclass) |
| if (known_ge (GET_MODE_SIZE (mode), fieldsize) |
| && known_eq (GET_MODE_PRECISION (mode), |
| GET_MODE_BITSIZE (mode)) |
| && known_le (GET_MODE_SIZE (mode), len)) |
| { |
| tree ret = lang_hooks.types.type_for_mode (mode, 1); |
| if (ret && TYPE_MODE (ret) == mode) |
| return ret; |
| } |
| } |
| |
| for (int i = 0; i < NUM_INT_N_ENTS; i ++) |
| if (int_n_enabled_p[i] |
| && int_n_data[i].bitsize >= (unsigned) (BITS_PER_UNIT * fieldsize) |
| && int_n_trees[i].unsigned_type) |
| { |
| tree ret = int_n_trees[i].unsigned_type; |
| mode = TYPE_MODE (ret); |
| if (known_ge (GET_MODE_SIZE (mode), fieldsize) |
| && known_eq (GET_MODE_PRECISION (mode), |
| GET_MODE_BITSIZE (mode)) |
| && known_le (GET_MODE_SIZE (mode), len)) |
| return ret; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* Similar to native_encode_expr, but also handle CONSTRUCTORs, VCEs, |
| NON_LVALUE_EXPRs and nops. If MASK is non-NULL (then PTR has |
| to be non-NULL and OFF zero), then in addition to filling the |
| bytes pointed by PTR with the value also clear any bits pointed |
| by MASK that are known to be initialized, keep them as is for |
| e.g. uninitialized padding bits or uninitialized fields. */ |
| |
| int |
| native_encode_initializer (tree init, unsigned char *ptr, int len, |
| int off, unsigned char *mask) |
| { |
| int r; |
| |
| /* We don't support starting at negative offset and -1 is special. */ |
| if (off < -1 || init == NULL_TREE) |
| return 0; |
| |
| gcc_assert (mask == NULL || (off == 0 && ptr)); |
| |
| STRIP_NOPS (init); |
| switch (TREE_CODE (init)) |
| { |
| case VIEW_CONVERT_EXPR: |
| case NON_LVALUE_EXPR: |
| return native_encode_initializer (TREE_OPERAND (init, 0), ptr, len, off, |
| mask); |
| default: |
| r = native_encode_expr (init, ptr, len, off); |
| if (mask) |
| memset (mask, 0, r); |
| return r; |
| case CONSTRUCTOR: |
| tree type = TREE_TYPE (init); |
| HOST_WIDE_INT total_bytes = int_size_in_bytes (type); |
| if (total_bytes < 0) |
| return 0; |
| if ((off == -1 && total_bytes > len) || off >= total_bytes) |
| return 0; |
| int o = off == -1 ? 0 : off; |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| tree min_index; |
| unsigned HOST_WIDE_INT cnt; |
| HOST_WIDE_INT curpos = 0, fieldsize, valueinit = -1; |
| constructor_elt *ce; |
| |
| if (!TYPE_DOMAIN (type) |
| || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST) |
| return 0; |
| |
| fieldsize = int_size_in_bytes (TREE_TYPE (type)); |
| if (fieldsize <= 0) |
| return 0; |
| |
| min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); |
| if (ptr) |
| memset (ptr, '\0', MIN (total_bytes - off, len)); |
| |
| for (cnt = 0; ; cnt++) |
| { |
| tree val = NULL_TREE, index = NULL_TREE; |
| HOST_WIDE_INT pos = curpos, count = 0; |
| bool full = false; |
| if (vec_safe_iterate (CONSTRUCTOR_ELTS (init), cnt, &ce)) |
| { |
| val = ce->value; |
| index = ce->index; |
| } |
| else if (mask == NULL |
| || CONSTRUCTOR_NO_CLEARING (init) |
| || curpos >= total_bytes) |
| break; |
| else |
| pos = total_bytes; |
| |
| if (index && TREE_CODE (index) == RANGE_EXPR) |
| { |
| if (TREE_CODE (TREE_OPERAND (index, 0)) != INTEGER_CST |
| || TREE_CODE (TREE_OPERAND (index, 1)) != INTEGER_CST) |
| return 0; |
| offset_int wpos |
| = wi::sext (wi::to_offset (TREE_OPERAND (index, 0)) |
| - wi::to_offset (min_index), |
| TYPE_PRECISION (sizetype)); |
| wpos *= fieldsize; |
| if (!wi::fits_shwi_p (pos)) |
| return 0; |
| pos = wpos.to_shwi (); |
| offset_int wcount |
| = wi::sext (wi::to_offset (TREE_OPERAND (index, 1)) |
| - wi::to_offset (TREE_OPERAND (index, 0)), |
| TYPE_PRECISION (sizetype)); |
| if (!wi::fits_shwi_p (wcount)) |
| return 0; |
| count = wcount.to_shwi (); |
| } |
| else if (index) |
| { |
| if (TREE_CODE (index) != INTEGER_CST) |
| return 0; |
| offset_int wpos |
| = wi::sext (wi::to_offset (index) |
| - wi::to_offset (min_index), |
| TYPE_PRECISION (sizetype)); |
| wpos *= fieldsize; |
| if (!wi::fits_shwi_p (wpos)) |
| return 0; |
| pos = wpos.to_shwi (); |
| } |
| |
| if (mask && !CONSTRUCTOR_NO_CLEARING (init) && curpos != pos) |
| { |
| if (valueinit == -1) |
| { |
| tree zero = build_zero_cst (TREE_TYPE (type)); |
| r = native_encode_initializer (zero, ptr + curpos, |
| fieldsize, 0, |
| mask + curpos); |
| if (TREE_CODE (zero) == CONSTRUCTOR) |
| ggc_free (zero); |
| if (!r) |
| return 0; |
| valueinit = curpos; |
| curpos += fieldsize; |
| } |
| while (curpos != pos) |
| { |
| memcpy (ptr + curpos, ptr + valueinit, fieldsize); |
| memcpy (mask + curpos, mask + valueinit, fieldsize); |
| curpos += fieldsize; |
| } |
| } |
| |
| curpos = pos; |
| if (val) |
| do |
| { |
| if (off == -1 |
| || (curpos >= off |
| && (curpos + fieldsize |
| <= (HOST_WIDE_INT) off + len))) |
| { |
| if (full) |
| { |
| if (ptr) |
| memcpy (ptr + (curpos - o), ptr + (pos - o), |
| fieldsize); |
| if (mask) |
| memcpy (mask + curpos, mask + pos, fieldsize); |
| } |
| else if (!native_encode_initializer (val, |
| ptr |
| ? ptr + curpos - o |
| : NULL, |
| fieldsize, |
| off == -1 ? -1 |
| : 0, |
| mask |
| ? mask + curpos |
| : NULL)) |
| return 0; |
| else |
| { |
| full = true; |
| pos = curpos; |
| } |
| } |
| else if (curpos + fieldsize > off |
| && curpos < (HOST_WIDE_INT) off + len) |
| { |
| /* Partial overlap. */ |
| unsigned char *p = NULL; |
| int no = 0; |
| int l; |
| gcc_assert (mask == NULL); |
| if (curpos >= off) |
| { |
| if (ptr) |
| p = ptr + curpos - off; |
| l = MIN ((HOST_WIDE_INT) off + len - curpos, |
| fieldsize); |
| } |
| else |
| { |
| p = ptr; |
| no = off - curpos; |
| l = len; |
| } |
| if (!native_encode_initializer (val, p, l, no, NULL)) |
| return 0; |
| } |
| curpos += fieldsize; |
| } |
| while (count-- != 0); |
| } |
| return MIN (total_bytes - off, len); |
| } |
| else if (TREE_CODE (type) == RECORD_TYPE |
| || TREE_CODE (type) == UNION_TYPE) |
| { |
| unsigned HOST_WIDE_INT cnt; |
| constructor_elt *ce; |
| tree fld_base = TYPE_FIELDS (type); |
| tree to_free = NULL_TREE; |
| |
| gcc_assert (TREE_CODE (type) == RECORD_TYPE || mask == NULL); |
| if (ptr != NULL) |
| memset (ptr, '\0', MIN (total_bytes - o, len)); |
| for (cnt = 0; ; cnt++) |
| { |
| tree val = NULL_TREE, field = NULL_TREE; |
| HOST_WIDE_INT pos = 0, fieldsize; |
| unsigned HOST_WIDE_INT bpos = 0, epos = 0; |
| |
| if (to_free) |
| { |
| ggc_free (to_free); |
| to_free = NULL_TREE; |
| } |
| |
| if (vec_safe_iterate (CONSTRUCTOR_ELTS (init), cnt, &ce)) |
| { |
| val = ce->value; |
| field = ce->index; |
| if (field == NULL_TREE) |
| return 0; |
| |
| pos = int_byte_position (field); |
| if (off != -1 && (HOST_WIDE_INT) off + len <= pos) |
| continue; |
| } |
| else if (mask == NULL |
| || CONSTRUCTOR_NO_CLEARING (init)) |
| break; |
| else |
| pos = total_bytes; |
| |
| if (mask && !CONSTRUCTOR_NO_CLEARING (init)) |
| { |
| tree fld; |
| for (fld = fld_base; fld; fld = DECL_CHAIN (fld)) |
| { |
| if (TREE_CODE (fld) != FIELD_DECL) |
| continue; |
| if (fld == field) |
| break; |
| if (DECL_PADDING_P (fld)) |
| continue; |
| if (DECL_SIZE_UNIT (fld) == NULL_TREE |
| || !tree_fits_shwi_p (DECL_SIZE_UNIT (fld))) |
| return 0; |
| if (integer_zerop (DECL_SIZE_UNIT (fld))) |
| continue; |
| break; |
| } |
| if (fld == NULL_TREE) |
| { |
| if (ce == NULL) |
| break; |
| return 0; |
| } |
| fld_base = DECL_CHAIN (fld); |
| if (fld != field) |
| { |
| cnt--; |
| field = fld; |
| pos = int_byte_position (field); |
| val = build_zero_cst (TREE_TYPE (fld)); |
| if (TREE_CODE (val) == CONSTRUCTOR) |
| to_free = val; |
| } |
| } |
| |
| if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE |
| && TYPE_DOMAIN (TREE_TYPE (field)) |
| && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))) |
| { |
| if (mask || off != -1) |
| return 0; |
| if (val == NULL_TREE) |
| continue; |
| if (TREE_CODE (TREE_TYPE (val)) != ARRAY_TYPE) |
| return 0; |
| fieldsize = int_size_in_bytes (TREE_TYPE (val)); |
| if (fieldsize < 0 |
| || (int) fieldsize != fieldsize |
| || (pos + fieldsize) > INT_MAX) |
| return 0; |
| if (pos + fieldsize > total_bytes) |
| { |
| if (ptr != NULL && total_bytes < len) |
| memset (ptr + total_bytes, '\0', |
| MIN (pos + fieldsize, len) - total_bytes); |
| total_bytes = pos + fieldsize; |
| } |
| } |
| else |
| { |
| if (DECL_SIZE_UNIT (field) == NULL_TREE |
| || !tree_fits_shwi_p (DECL_SIZE_UNIT (field))) |
| return 0; |
| fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field)); |
| } |
| if (fieldsize == 0) |
| continue; |
| |
| if (DECL_BIT_FIELD (field)) |
| { |
| if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field))) |
| return 0; |
| fieldsize = TYPE_PRECISION (TREE_TYPE (field)); |
| bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)); |
| if (bpos % BITS_PER_UNIT) |
| bpos %= BITS_PER_UNIT; |
| else |
| bpos = 0; |
| fieldsize += bpos; |
| epos = fieldsize % BITS_PER_UNIT; |
| fieldsize += BITS_PER_UNIT - 1; |
| fieldsize /= BITS_PER_UNIT; |
| } |
| |
| if (off != -1 && pos + fieldsize <= off) |
| continue; |
| |
| if (val == NULL_TREE) |
| continue; |
| |
| if (DECL_BIT_FIELD (field)) |
| { |
| /* FIXME: Handle PDP endian. */ |
| if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) |
| return 0; |
| |
| if (TREE_CODE (val) != INTEGER_CST) |
| return 0; |
| |
| tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field); |
| tree repr_type = NULL_TREE; |
| HOST_WIDE_INT rpos = 0; |
| if (repr && INTEGRAL_TYPE_P (TREE_TYPE (repr))) |
| { |
| rpos = int_byte_position (repr); |
| repr_type = TREE_TYPE (repr); |
| } |
| else |
| { |
| repr_type = find_bitfield_repr_type (fieldsize, len); |
| if (repr_type == NULL_TREE) |
| return 0; |
| HOST_WIDE_INT repr_size = int_size_in_bytes (repr_type); |
| gcc_assert (repr_size > 0 && repr_size <= len); |
| if (pos + repr_size <= o + len) |
| rpos = pos; |
| else |
| { |
| rpos = o + len - repr_size; |
| gcc_assert (rpos <= pos); |
| } |
| } |
| |
| if (rpos > pos) |
| return 0; |
| wide_int w = wi::to_wide (val, TYPE_PRECISION (repr_type)); |
| int diff = (TYPE_PRECISION (repr_type) |
| - TYPE_PRECISION (TREE_TYPE (field))); |
| HOST_WIDE_INT bitoff = (pos - rpos) * BITS_PER_UNIT + bpos; |
| if (!BYTES_BIG_ENDIAN) |
| w = wi::lshift (w, bitoff); |
| else |
| w = wi::lshift (w, diff - bitoff); |
| val = wide_int_to_tree (repr_type, w); |
| |
| unsigned char buf[MAX_BITSIZE_MODE_ANY_INT |
| / BITS_PER_UNIT + 1]; |
| int l = native_encode_int (val, buf, sizeof buf, 0); |
| if (l * BITS_PER_UNIT != TYPE_PRECISION (repr_type)) |
| return 0; |
| |
| if (ptr == NULL) |
| continue; |
| |
| /* If the bitfield does not start at byte boundary, handle |
| the partial byte at the start. */ |
| if (bpos |
| && (off == -1 || (pos >= off && len >= 1))) |
| { |
| if (!BYTES_BIG_ENDIAN) |
| { |
| int msk = (1 << bpos) - 1; |
| buf[pos - rpos] &= ~msk; |
| buf[pos - rpos] |= ptr[pos - o] & msk; |
| if (mask) |
| { |
| if (fieldsize > 1 || epos == 0) |
| mask[pos] &= msk; |
| else |
| mask[pos] &= (msk | ~((1 << epos) - 1)); |
| } |
| } |
| else |
| { |
| int msk = (1 << (BITS_PER_UNIT - bpos)) - 1; |
| buf[pos - rpos] &= msk; |
| buf[pos - rpos] |= ptr[pos - o] & ~msk; |
| if (mask) |
| { |
| if (fieldsize > 1 || epos == 0) |
| mask[pos] &= ~msk; |
| else |
| mask[pos] &= (~msk |
| | ((1 << (BITS_PER_UNIT - epos)) |
| - 1)); |
| } |
| } |
| } |
| /* If the bitfield does not end at byte boundary, handle |
| the partial byte at the end. */ |
| if (epos |
| && (off == -1 |
| || pos + fieldsize <= (HOST_WIDE_INT) off + len)) |
| { |
| if (!BYTES_BIG_ENDIAN) |
| { |
| int msk = (1 << epos) - 1; |
| buf[pos - rpos + fieldsize - 1] &= msk; |
| buf[pos - rpos + fieldsize - 1] |
| |= ptr[pos + fieldsize - 1 - o] & ~msk; |
| if (mask && (fieldsize > 1 || bpos == 0)) |
| mask[pos + fieldsize - 1] &= ~msk; |
| } |
| else |
| { |
| int msk = (1 << (BITS_PER_UNIT - epos)) - 1; |
| buf[pos - rpos + fieldsize - 1] &= ~msk; |
| buf[pos - rpos + fieldsize - 1] |
| |= ptr[pos + fieldsize - 1 - o] & msk; |
| if (mask && (fieldsize > 1 || bpos == 0)) |
| mask[pos + fieldsize - 1] &= msk; |
| } |
| } |
| if (off == -1 |
| || (pos >= off |
| && (pos + fieldsize <= (HOST_WIDE_INT) off + len))) |
| { |
| memcpy (ptr + pos - o, buf + (pos - rpos), fieldsize); |
| if (mask && (fieldsize > (bpos != 0) + (epos != 0))) |
| memset (mask + pos + (bpos != 0), 0, |
| fieldsize - (bpos != 0) - (epos != 0)); |
| } |
| else |
| { |
| /* Partial overlap. */ |
| HOST_WIDE_INT fsz = fieldsize; |
| gcc_assert (mask == NULL); |
| if (pos < off) |
| { |
| fsz -= (off - pos); |
| pos = off; |
| } |
| if (pos + fsz > (HOST_WIDE_INT) off + len) |
| fsz = (HOST_WIDE_INT) off + len - pos; |
| memcpy (ptr + pos - off, buf + (pos - rpos), fsz); |
| } |
| continue; |
| } |
| |
| if (off == -1 |
| || (pos >= off |
| && (pos + fieldsize <= (HOST_WIDE_INT) off + len))) |
| { |
| int fldsize = fieldsize; |
| if (off == -1) |
| { |
| tree fld = DECL_CHAIN (field); |
| while (fld) |
| { |
| if (TREE_CODE (fld) == FIELD_DECL) |
| break; |
| fld = DECL_CHAIN (fld); |
| } |
| if (fld == NULL_TREE) |
| fldsize = len - pos; |
| } |
| r = native_encode_initializer (val, ptr ? ptr + pos - o |
| : NULL, |
| fldsize, |
| off == -1 ? -1 : 0, |
| mask ? mask + pos : NULL); |
| if (!r) |
| return 0; |
| if (off == -1 |
| && fldsize != fieldsize |
| && r > fieldsize |
| && pos + r > total_bytes) |
| total_bytes = pos + r; |
| } |
| else |
| { |
| /* Partial overlap. */ |
| unsigned char *p = NULL; |
| int no = 0; |
| int l; |
| gcc_assert (mask == NULL); |
| if (pos >= off) |
| { |
| if (ptr) |
| p = ptr + pos - off; |
| l = MIN ((HOST_WIDE_INT) off + len - pos, |
| fieldsize); |
| } |
| else |
| { |
| p = ptr; |
| no = off - pos; |
| l = len; |
| } |
| if (!native_encode_initializer (val, p, l, no, NULL)) |
| return 0; |
| } |
| } |
| return MIN (total_bytes - off, len); |
| } |
| return 0; |
| } |
| } |
| |
| |
| /* Subroutine of native_interpret_expr. Interpret the contents of |
| the buffer PTR of length LEN as an INTEGER_CST of type TYPE. |
| If the buffer cannot be interpreted, return NULL_TREE. */ |
| |
| static tree |
| native_interpret_int (tree type, const unsigned char *ptr, int len) |
| { |
| int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)); |
| |
| if (total_bytes > len |
| || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) |
| return NULL_TREE; |
| |
| wide_int result = wi::from_buffer (ptr, total_bytes); |
| |
| return wide_int_to_tree (type, result); |
| } |
| |
| |
| /* Subroutine of native_interpret_expr. Interpret the contents of |
| the buffer PTR of length LEN as a FIXED_CST of type TYPE. |
| If the buffer cannot be interpreted, return NULL_TREE. */ |
| |
| static tree |
| native_interpret_fixed (tree type, const unsigned char *ptr, int len) |
| { |
| scalar_mode mode = SCALAR_TYPE_MODE (type); |
| int total_bytes = GET_MODE_SIZE (mode); |
| double_int result; |
| FIXED_VALUE_TYPE fixed_value; |
| |
| if (total_bytes > len |
| || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) |
| return NULL_TREE; |
| |
| result = double_int::from_buffer (ptr, total_bytes); |
| fixed_value = fixed_from_double_int (result, mode); |
| |
| return build_fixed (type, fixed_value); |
| } |
| |
| |
| /* Subroutine of native_interpret_expr. Interpret the contents of |
| the buffer PTR of length LEN as a REAL_CST of type TYPE. |
| If the buffer cannot be interpreted, return NULL_TREE. */ |
| |
| static tree |
| native_interpret_real (tree type, const unsigned char *ptr, int len) |
| { |
| scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (type); |
| int total_bytes = GET_MODE_SIZE (mode); |
| 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 |
| up to 192 bits. */ |
| REAL_VALUE_TYPE r; |
| long tmp[6]; |
| |
| if (total_bytes > len || total_bytes > 24) |
| return NULL_TREE; |
| int words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD; |
| |
| memset (tmp, 0, sizeof (tmp)); |
| for (int bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT; |
| bitpos += BITS_PER_UNIT) |
| { |
| /* 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) |
| { |
| int word = byte / UNITS_PER_WORD; |
| if (WORDS_BIG_ENDIAN) |
| word = (words - 1) - word; |
| offset = word * UNITS_PER_WORD; |
| if (BYTES_BIG_ENDIAN) |
| offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); |
| else |
| offset += byte % UNITS_PER_WORD; |
| } |
| else |
| { |
| 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); |
| } |
| |
| real_from_target (&r, tmp, mode); |
| tree ret = build_real (type, r); |
| if (MODE_COMPOSITE_P (mode)) |
| { |
| /* For floating point values in composite modes, punt if this folding |
| doesn't preserve bit representation. As the mode doesn't have fixed |
| precision while GCC pretends it does, there could be valid values that |
| GCC can't really represent accurately. See PR95450. */ |
| unsigned char buf[24]; |
| if (native_encode_expr (ret, buf, total_bytes, 0) != total_bytes |
| || memcmp (ptr, buf, total_bytes) != 0) |
| ret = NULL_TREE; |
| } |
| return ret; |
| } |
| |
| |
| /* Subroutine of native_interpret_expr. Interpret the contents of |
| the buffer PTR of length LEN as a COMPLEX_CST of type TYPE. |
| If the buffer cannot be interpreted, return NULL_TREE. */ |
| |
| static tree |
| native_interpret_complex (tree type, const unsigned char *ptr, int len) |
| { |
| tree etype, rpart, ipart; |
| int size; |
| |
| etype = TREE_TYPE (type); |
| size = GET_MODE_SIZE (SCALAR_TYPE_MODE (etype)); |
| if (size * 2 > len) |
| return NULL_TREE; |
| rpart = native_interpret_expr (etype, ptr, size); |
| if (!rpart) |
| return NULL_TREE; |
| ipart = native_interpret_expr (etype, ptr+size, size); |
| if (!ipart) |
| return NULL_TREE; |
| return build_complex (type, rpart, ipart); |
| } |
| |
| /* Read a vector of type TYPE from the target memory image given by BYTES, |
| which contains LEN bytes. The vector is known to be encodable using |
| NPATTERNS interleaved patterns with NELTS_PER_PATTERN elements each. |
| |
| Return the vector on success, otherwise return null. */ |
| |
| static tree |
| native_interpret_vector_part (tree type, const unsigned char *bytes, |
| unsigned int len, unsigned int npatterns, |
| unsigned int nelts_per_pattern) |
| { |
| tree elt_type = TREE_TYPE (type); |
| if (VECTOR_BOOLEAN_TYPE_P (type) |
| && TYPE_PRECISION (elt_type) <= BITS_PER_UNIT) |
| { |
| /* This is the only case in which elements can be smaller than a byte. |
| Element 0 is always in the lsb of the containing byte. */ |
| unsigned int elt_bits = TYPE_PRECISION (elt_type); |
| if (elt_bits * npatterns * nelts_per_pattern > len * BITS_PER_UNIT) |
| return NULL_TREE; |
| |
| tree_vector_builder builder (type, npatterns, nelts_per_pattern); |
| for (unsigned int i = 0; i < builder.encoded_nelts (); ++i) |
| { |
| unsigned int bit_index = i * elt_bits; |
| unsigned int byte_index = bit_index / BITS_PER_UNIT; |
| unsigned int lsb = bit_index % BITS_PER_UNIT; |
| builder.quick_push (bytes[byte_index] & (1 << lsb) |
| ? build_all_ones_cst (elt_type) |
| : build_zero_cst (elt_type)); |
| } |
| return builder.build (); |
| } |
| |
| unsigned int elt_bytes = tree_to_uhwi (TYPE_SIZE_UNIT (elt_type)); |
| if (elt_bytes * npatterns * nelts_per_pattern > len) |
| return NULL_TREE; |
| |
| tree_vector_builder builder (type, npatterns, nelts_per_pattern); |
| for (unsigned int i = 0; i < builder.encoded_nelts (); ++i) |
| { |
| tree elt = native_interpret_expr (elt_type, bytes, elt_bytes); |
| if (!elt) |
| return NULL_TREE; |
| builder.quick_push (elt); |
| bytes += elt_bytes; |
| } |
| return builder.build (); |
| } |
| |
| /* Subroutine of native_interpret_expr. Interpret the contents of |
| the buffer PTR of length LEN as a VECTOR_CST of type TYPE. |
| If the buffer cannot be interpreted, return NULL_TREE. */ |
| |
| static tree |
| native_interpret_vector (tree type, const unsigned char *ptr, unsigned int len) |
| { |
| tree etype; |
| unsigned int size; |
| unsigned HOST_WIDE_INT count; |
| |
| etype = TREE_TYPE (type); |
| size = GET_MODE_SIZE (SCALAR_TYPE_MODE (etype)); |
| if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&count) |
| || size * count > len) |
| return NULL_TREE; |
| |
| return native_interpret_vector_part (type, ptr, len, count, 1); |
| } |
| |
| |
| /* Subroutine of fold_view_convert_expr. Interpret the contents of |
| the buffer PTR of length LEN as a constant of type TYPE. For |
| INTEGRAL_TYPE_P we return an INTEGER_CST, for SCALAR_FLOAT_TYPE_P |
| we return a REAL_CST, etc... If the buffer cannot be interpreted, |
| return NULL_TREE. */ |
| |
| tree |
| native_interpret_expr (tree type, const unsigned char *ptr, int len) |
| { |
| switch (TREE_CODE (type)) |
| { |
| case INTEGER_TYPE: |
| case ENUMERAL_TYPE: |
| case BOOLEAN_TYPE: |
| case POINTER_TYPE: |
| case REFERENCE_TYPE: |
| return native_interpret_int (type, ptr, len); |
| |
| case REAL_TYPE: |
| return native_interpret_real (type, ptr, len); |
| |
| case FIXED_POINT_TYPE: |
| return native_interpret_fixed (type, ptr, len); |
| |
| case COMPLEX_TYPE: |
| return native_interpret_complex (type, ptr, len); |
| |
| case VECTOR_TYPE: |
| return native_interpret_vector (type, ptr, len); |
| |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| /* Returns true if we can interpret the contents of a native encoding |
| as TYPE. */ |
| |
| bool |
| can_native_interpret_type_p (tree type) |
| { |
| switch (TREE_CODE (type)) |
| { |
| case INTEGER_TYPE: |
| case ENUMERAL_TYPE: |
| case BOOLEAN_TYPE: |
| case POINTER_TYPE: |
| case REFERENCE_TYPE: |
| case FIXED_POINT_TYPE: |
| case REAL_TYPE: |
| case COMPLEX_TYPE: |
| case VECTOR_TYPE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /* Attempt to interpret aggregate of TYPE from bytes encoded in target |
| byte order at PTR + OFF with LEN bytes. Does not handle unions. */ |
| |
| tree |
| native_interpret_aggregate (tree type, const unsigned char *ptr, int off, |
| int len) |
| { |
| vec<constructor_elt, va_gc> *elts = NULL; |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| HOST_WIDE_INT eltsz = int_size_in_bytes (TREE_TYPE (type)); |
| if (eltsz < 0 || eltsz > len || TYPE_DOMAIN (type) == NULL_TREE) |
| return NULL_TREE; |
| |
| HOST_WIDE_INT cnt = 0; |
| if (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) |
| { |
| if (!tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) |
| return NULL_TREE; |
| cnt = tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1; |
| } |
| if (eltsz == 0) |
| cnt = 0; |
| HOST_WIDE_INT pos = 0; |
| for (HOST_WIDE_INT i = 0; i < cnt; i++, pos += eltsz) |
| { |
| tree v = NULL_TREE; |
| if (pos >= len || pos + eltsz > len) |
| return NULL_TREE; |
| if (can_native_interpret_type_p (TREE_TYPE (type))) |
| { |
| v = native_interpret_expr (TREE_TYPE (type), |
| ptr + off + pos, eltsz); |
| if (v == NULL_TREE) |
| return NULL_TREE; |
| } |
| else if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE |
| || TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE) |
| v = native_interpret_aggregate (TREE_TYPE (type), ptr, off + pos, |
| eltsz); |
| if (v == NULL_TREE) |
| return NULL_TREE; |
| CONSTRUCTOR_APPEND_ELT (elts, size_int (i), v); |
| } |
| return build_constructor (type, elts); |
| } |
| if (TREE_CODE (type) != RECORD_TYPE) |
| return NULL_TREE; |
| for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) |
| { |
| if (TREE_CODE (field) != FIELD_DECL || DECL_PADDING_P (field)) |
| continue; |
| tree fld = field; |
| HOST_WIDE_INT bitoff = 0, pos = 0, sz = 0; |
| int diff = 0; |
| tree v = NULL_TREE; |
| if (DECL_BIT_FIELD (field)) |
| { |
| fld = DECL_BIT_FIELD_REPRESENTATIVE (field); |
| if (fld && INTEGRAL_TYPE_P (TREE_TYPE (fld))) |
| { |
| poly_int64 bitoffset; |
| poly_uint64 field_offset, fld_offset; |
| if (poly_int_tree_p (DECL_FIELD_OFFSET (field), &field_offset) |
| && poly_int_tree_p (DECL_FIELD_OFFSET (fld), &fld_offset)) |
| bitoffset = (field_offset - fld_offset) * BITS_PER_UNIT; |
| else |
| bitoffset = 0; |
| bitoffset += (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)) |
| - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld))); |
| diff = (TYPE_PRECISION (TREE_TYPE (fld)) |
| - TYPE_PRECISION (TREE_TYPE (field))); |
| if (!bitoffset.is_constant (&bitoff) |
| || bitoff < 0 |
| || bitoff > diff) |
| return NULL_TREE; |
| } |
| else |
| { |
| if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field))) |
| return NULL_TREE; |
| int fieldsize = TYPE_PRECISION (TREE_TYPE (field)); |
| int bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)); |
| bpos %= BITS_PER_UNIT; |
| fieldsize += bpos; |
| fieldsize += BITS_PER_UNIT - 1; |
| fieldsize /= BITS_PER_UNIT; |
| tree repr_type = find_bitfield_repr_type (fieldsize, len); |
| if (repr_type == NULL_TREE) |
| return NULL_TREE; |
| sz = int_size_in_bytes (repr_type); |
| if (sz < 0 || sz > len) |
| return NULL_TREE; |
| pos = int_byte_position (field); |
| if (pos < 0 || pos > len || pos + fieldsize > len) |
| return NULL_TREE; |
| HOST_WIDE_INT rpos; |
| if (pos + sz <= len) |
| rpos = pos; |
| else |
| { |
| rpos = len - sz; |
| gcc_assert (rpos <= pos); |
| } |
| bitoff = (HOST_WIDE_INT) (pos - rpos) * BITS_PER_UNIT + bpos; |
| pos = rpos; |
| diff = (TYPE_PRECISION (repr_type) |
| - TYPE_PRECISION (TREE_TYPE (field))); |
| v = native_interpret_expr (repr_type, ptr + off + pos, sz); |
| if (v == NULL_TREE) |
| return NULL_TREE; |
| fld = NULL_TREE; |
| } |
| } |
| |
| if (fld) |
| { |
| sz = int_size_in_bytes (TREE_TYPE (fld)); |
| if (sz < 0 || sz > len) |
| return NULL_TREE; |
| tree byte_pos = byte_position (fld); |
| if (!tree_fits_shwi_p (byte_pos)) |
| return NULL_TREE; |
| pos = tree_to_shwi (byte_pos); |
| if (pos < 0 || pos > len || pos + sz > len) |
| return NULL_TREE; |
| } |
| if (fld == NULL_TREE) |
| /* Already handled above. */; |
| else if (can_native_interpret_type_p (TREE_TYPE (fld))) |
| { |
| v = native_interpret_expr (TREE_TYPE (fld), |
| ptr + off + pos, sz); |
| if (v == NULL_TREE) |
| return NULL_TREE; |
| } |
| else if (TREE_CODE (TREE_TYPE (fld)) == RECORD_TYPE |
| || TREE_CODE (TREE_TYPE (fld)) == ARRAY_TYPE) |
| v = native_interpret_aggregate (TREE_TYPE (fld), ptr, off + pos, sz); |
| if (v == NULL_TREE) |
| return NULL_TREE; |
| if (fld != field) |
| { |
| if (TREE_CODE (v) != INTEGER_CST) |
| return NULL_TREE; |
| |
| /* FIXME: Figure out how to handle PDP endian bitfields. */ |
| if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) |
| return NULL_TREE; |
| if (!BYTES_BIG_ENDIAN) |
| v = wide_int_to_tree (TREE_TYPE (field), |
| wi::lrshift (wi::to_wide (v), bitoff)); |
| else |
| v = wide_int_to_tree (TREE_TYPE (field), |
| wi::lrshift (wi::to_wide (v), |
| diff - bitoff)); |
| } |
| CONSTRUCTOR_APPEND_ELT (elts, field, v); |
| } |
| return build_constructor (type, elts); |
| } |
| |
| /* Routines for manipulation of native_encode_expr encoded data if the encoded |
| or extracted constant positions and/or sizes aren't byte aligned. */ |
| |
| /* Shift left the bytes in PTR of SZ elements by AMNT bits, carrying over the |
| bits between adjacent elements. AMNT should be within |
| [0, BITS_PER_UNIT). |
| Example, AMNT = 2: |
| 00011111|11100000 << 2 = 01111111|10000000 |
| PTR[1] | PTR[0] PTR[1] | PTR[0]. */ |
| |
| void |
| shift_bytes_in_array_left (unsigned char *ptr, unsigned int sz, |
| unsigned int amnt) |
| { |
| if (amnt == 0) |
| return; |
| |
| unsigned char carry_over = 0U; |
| unsigned char carry_mask = (~0U) << (unsigned char) (BITS_PER_UNIT - amnt); |
| unsigned char clear_mask = (~0U) << amnt; |
| |
| for (unsigned int i = 0; i < sz; i++) |
| { |
| unsigned prev_carry_over = carry_over; |
| carry_over = (ptr[i] & carry_mask) >> (BITS_PER_UNIT - amnt); |
| |
| ptr[i] <<= amnt; |
| if (i != 0) |
| { |
| ptr[i] &= clear_mask; |
| ptr[i] |= prev_carry_over; |
| } |
| } |
| } |
| |
| /* Like shift_bytes_in_array_left but for big-endian. |
| Shift right the bytes in PTR of SZ elements by AMNT bits, carrying over the |
| bits between adjacent elements. AMNT should be within |
| [0, BITS_PER_UNIT). |
| Example, AMNT = 2: |
| 00011111|11100000 >> 2 = 00000111|11111000 |
| PTR[0] | PTR[1] PTR[0] | PTR[1]. */ |
| |
| void |
| shift_bytes_in_array_right (unsigned char *ptr, unsigned int sz, |
| unsigned int amnt) |
| { |
| if (amnt == 0) |
| return; |
| |
| unsigned char carry_over = 0U; |
| unsigned char carry_mask = ~(~0U << amnt); |
| |
| for (unsigned int i = 0; i < sz; i++) |
| { |
| unsigned prev_carry_over = carry_over; |
| carry_over = ptr[i] & carry_mask; |
| |
| carry_over <<= (unsigned char) BITS_PER_UNIT - amnt; |
| ptr[i] >>= amnt; |
| ptr[i] |= prev_carry_over; |
| } |
| } |
| |
| /* Try to view-convert VECTOR_CST EXPR to VECTOR_TYPE TYPE by operating |
| directly on the VECTOR_CST encoding, in a way that works for variable- |
| length vectors. Return the resulting VECTOR_CST on success or null |
| on failure. */ |
| |
| static tree |
| fold_view_convert_vector_encoding (tree type, tree expr) |
| { |
| tree expr_type = TREE_TYPE (expr); |
| poly_uint64 type_bits, expr_bits; |
| if (!poly_int_tree_p (TYPE_SIZE (type), &type_bits) |
| || !poly_int_tree_p (TYPE_SIZE (expr_type), &expr_bits)) |
| return NULL_TREE; |
| |
| poly_uint64 type_units = TYPE_VECTOR_SUBPARTS (type); |
| poly_uint64 expr_units = TYPE_VECTOR_SUBPARTS (expr_type); |
| unsigned int type_elt_bits = vector_element_size (type_bits, type_units); |
| unsigned int expr_elt_bits = vector_element_size (expr_bits, expr_units); |
| |
| /* We can only preserve the semantics of a stepped pattern if the new |
| vector element is an integer of the same size. */ |
| if (VECTOR_CST_STEPPED_P (expr) |
| && (!INTEGRAL_TYPE_P (type) || type_elt_bits != expr_elt_bits)) |
| return NULL_TREE; |
| |
| /* The number of bits needed to encode one element from every pattern |
| of the original vector. */ |
| unsigned int expr_sequence_bits |
| = VECTOR_CST_NPATTERNS (expr) * expr_elt_bits; |
| |
| /* The number of bits needed to encode one element from every pattern |
| of the result. */ |
| unsigned int type_sequence_bits |
| = least_common_multiple (expr_sequence_bits, type_elt_bits); |
| |
| /* Don't try to read more bytes than are available, which can happen |
| for constant-sized vectors if TYPE has larger elements than EXPR_TYPE. |
| The general VIEW_CONVERT handling can cope with that case, so there's |
| no point complicating things here. */ |
| unsigned int nelts_per_pattern = VECTOR_CST_NELTS_PER_PATTERN (expr); |
| unsigned int buffer_bytes = CEIL (nelts_per_pattern * type_sequence_bits, |
| BITS_PER_UNIT); |
| unsigned int buffer_bits = buffer_bytes * BITS_PER_UNIT; |
| if (known_gt (buffer_bits, expr_bits)) |
| return NULL_TREE; |
| |
| /* Get enough bytes of EXPR to form the new encoding. */ |
| auto_vec<unsigned char, 128> buffer (buffer_bytes); |
| buffer.quick_grow (buffer_bytes); |
| if (native_encode_vector_part (expr, buffer.address (), buffer_bytes, 0, |
| buffer_bits / expr_elt_bits) |
| != (int) buffer_bytes) |
| return NULL_TREE; |
| |
| /* Reencode the bytes as TYPE. */ |
| unsigned int type_npatterns = type_sequence_bits / type_elt_bits; |
| return native_interpret_vector_part (type, &buffer[0], buffer.length (), |
| type_npatterns, nelts_per_pattern); |
| } |
| |
| /* Fold a VIEW_CONVERT_EXPR of a constant expression EXPR to type |
| TYPE at compile-time. If we're unable to perform the conversion |
| return NULL_TREE. */ |
| |
| static tree |
| fold_view_convert_expr (tree type, tree expr) |
| { |
| /* We support up to 512-bit values (for V8DFmode). */ |
| unsigned char buffer[64]; |
| int len; |
| |
| /* Check that the host and target are sane. */ |
| if (CHAR_BIT != 8 || BITS_PER_UNIT != 8) |
| return NULL_TREE; |
| |
| if (VECTOR_TYPE_P (type) && TREE_CODE (expr) == VECTOR_CST) |
| if (tree res = fold_view_convert_vector_encoding (type, expr)) |
| return res; |
| |
| len = native_encode_expr (expr, buffer, sizeof (buffer)); |
| if (len == 0) |
| return NULL_TREE; |
| |
| return native_interpret_expr (type, buffer, len); |
| } |
| |
| /* Build an expression for the address of T. Folds away INDIRECT_REF |
| to avoid confusing the gimplify process. */ |
| |
| tree |
| build_fold_addr_expr_with_type_loc (location_t loc, tree t, tree ptrtype) |
| { |
| /* The size of the object is not relevant when talking about its address. */ |
| if (TREE_CODE (t) == WITH_SIZE_EXPR) |
| t = TREE_OPERAND (t, 0); |
| |
| if (TREE_CODE (t) == INDIRECT_REF) |
| { |
| t = TREE_OPERAND (t, 0); |
| |
| if (TREE_TYPE (t) != ptrtype) |
| t = build1_loc (loc, NOP_EXPR, ptrtype, t); |
| } |
| else if (TREE_CODE (t) == MEM_REF |
| && integer_zerop (TREE_OPERAND (t, 1))) |
| { |
| t = TREE_OPERAND (t, 0); |
| |
| if (TREE_TYPE (t) != ptrtype) |
| t = fold_convert_loc (loc, ptrtype, t); |
| } |
| else if (TREE_CODE (t) == MEM_REF |
| && TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST) |
| return fold_binary (POINTER_PLUS_EXPR, ptrtype, |
| TREE_OPERAND (t, 0), |
| convert_to_ptrofftype (TREE_OPERAND (t, 1))); |
| else if (TREE_CODE (t) == VIEW_CONVERT_EXPR) |
| { |
| t = build_fold_addr_expr_loc (loc, TREE_OPERAND (t, 0)); |
| |
| if (TREE_TYPE (t) != ptrtype) |
| t = fold_convert_loc (loc, ptrtype, t); |
| } |
| else |
| t = build1_loc (loc, ADDR_EXPR, ptrtype, t); |
| |
| return t; |
| } |
| |
| /* Build an expression for the address of T. */ |
| |
| tree |
| build_fold_addr_expr_loc (location_t loc, tree t) |
| { |
| tree ptrtype = build_pointer_type (TREE_TYPE (t)); |
| |
| return build_fold_addr_expr_with_type_loc (loc, t, ptrtype); |
| } |
| |
| /* Fold a unary expression of code CODE and type TYPE with operand |
| OP0. Return the folded expression if folding is successful. |
| Otherwise, return NULL_TREE. */ |
| |
| tree |
| fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) |
| { |
| tree tem; |
| tree arg0; |
| enum tree_code_class kind = TREE_CODE_CLASS (code); |
| |
| gcc_assert (IS_EXPR_CODE_CLASS (kind) |
| && TREE_CODE_LENGTH (code) == 1); |
| |
| arg0 = op0; |
| if (arg0) |
| { |
| if (CONVERT_EXPR_CODE_P (code) |
| || code == FLOAT_EXPR || code == ABS_EXPR || code == NEGATE_EXPR) |
| { |
| /* Don't use STRIP_NOPS, because signedness of argument type |
| matters. */ |
| STRIP_SIGN_NOPS (arg0); |
| } |
| else |
| { |
| /* Strip any conversions that don't change the mode. This |
| is safe for every expression, except for a comparison |
| expression because its signedness is derived from its |
| operands. |
| |
| Note that this is done as an internal manipulation within |
| the constant folder, in order to find the simplest |
| representation of the arguments so that their form can be |
| studied. In any cases, the appropriate type conversions |
| should be put back in the tree that will get out of the |
| constant folder. */ |
| STRIP_NOPS (arg0); |
| } |
| |
| if (CONSTANT_CLASS_P (arg0)) |
| { |
| tree tem = const_unop (code, type, arg0); |
| if (tem) |
| { |
| if (TREE_TYPE (tem) != type) |
| tem = fold_convert_loc (loc, type, tem); |
| return tem; |
| } |
| } |
| } |
| |
| tem = generic_simplify (loc, code, type, op0); |
| if (tem) |
| return tem; |
| |
| if (TREE_CODE_CLASS (code) == tcc_unary) |
| { |
| if (TREE_CODE (arg0) == COMPOUND_EXPR) |
| return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), |
| fold_build1_loc (loc, code, type, |
| fold_convert_loc (loc, TREE_TYPE (op0), |
| TREE_OPERAND (arg0, 1)))); |
| else if (TREE_CODE (arg0) == COND_EXPR) |
| { |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| tree arg02 = TREE_OPERAND (arg0, 2); |
| if (! VOID_TYPE_P (TREE_TYPE (arg01))) |
| arg01 = fold_build1_loc (loc, code, type, |
| fold_convert_loc (loc, |
| TREE_TYPE (op0), arg01)); |
| if (! VOID_TYPE_P (TREE_TYPE (arg02))) |
| arg02 = fold_build1_loc (loc, code, type, |
| fold_convert_loc (loc, |
| TREE_TYPE (op0), arg02)); |
| tem = fold_build3_loc (loc, COND_EXPR, type, TREE_OPERAND (arg0, 0), |
| arg01, arg02); |
| |
| /* If this was a conversion, and all we did was to move into |
| inside the COND_EXPR, bring it back out. But leave it if |
| it is a conversion from integer to integer and the |
| result precision is no wider than a word since such a |
| conversion is cheap and may be optimized away by combine, |
| while it couldn't if it were outside the COND_EXPR. Then return |
| so we don't get into an infinite recursion loop taking the |
| conversion out and then back in. */ |
| |
| if ((CONVERT_EXPR_CODE_P (code) |
| || code == NON_LVALUE_EXPR) |
| && TREE_CODE (tem) == COND_EXPR |
| && TREE_CODE (TREE_OPERAND (tem, 1)) == code |
| && TREE_CODE (TREE_OPERAND (tem, 2)) == code |
| && ! VOID_TYPE_P (TREE_OPERAND (tem, 1)) |
| && ! VOID_TYPE_P (TREE_OPERAND (tem, 2)) |
| && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0)) |
| == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0))) |
| && (! (INTEGRAL_TYPE_P (TREE_TYPE (tem)) |
| && (INTEGRAL_TYPE_P |
| (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0)))) |
| && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD) |
| || flag_syntax_only)) |
| tem = build1_loc (loc, code, type, |
| build3 (COND_EXPR, |
| TREE_TYPE (TREE_OPERAND |
| (TREE_OPERAND (tem, 1), 0)), |
| TREE_OPERAND (tem, 0), |
| TREE_OPERAND (TREE_OPERAND (tem, 1), 0), |
| TREE_OPERAND (TREE_OPERAND (tem, 2), |
| 0))); |
| return tem; |
| } |
| } |
| |
| switch (code) |
| { |
| case NON_LVALUE_EXPR: |
| if (!maybe_lvalue_p (op0)) |
| return fold_convert_loc (loc, type, op0); |
| return NULL_TREE; |
| |
| CASE_CONVERT: |
| case FLOAT_EXPR: |
| case FIX_TRUNC_EXPR: |
| if (COMPARISON_CLASS_P (op0)) |
| { |
| /* If we have (type) (a CMP b) and type is an integral type, return |
| new expression involving the new type. Canonicalize |
| (type) (a CMP b) to (a CMP b) ? (type) true : (type) false for |
| non-integral type. |
| Do not fold the result as that would not simplify further, also |
| folding again results in recursions. */ |
| if (TREE_CODE (type) == BOOLEAN_TYPE) |
| return build2_loc (loc, TREE_CODE (op0), type, |
| TREE_OPERAND (op0, 0), |
| TREE_OPERAND (op0, 1)); |
| else if (!INTEGRAL_TYPE_P (type) && !VOID_TYPE_P (type) |
| && TREE_CODE (type) != VECTOR_TYPE) |
| return build3_loc (loc, COND_EXPR, type, op0, |
| constant_boolean_node (true, type), |
| constant_boolean_node (false, type)); |
| } |
| |
| /* Handle (T *)&A.B.C for A being of type T and B and C |
| living at offset zero. This occurs frequently in |
| C++ upcasting and then accessing the base. */ |
| if (TREE_CODE (op0) == ADDR_EXPR |
| && POINTER_TYPE_P (type) |
| && handled_component_p (TREE_OPERAND (op0, 0))) |
| { |
| poly_int64 bitsize, bitpos; |
| tree offset; |
| machine_mode mode; |
| int unsignedp, reversep, volatilep; |
| tree base |
| = get_inner_reference (TREE_OPERAND (op0, 0), &bitsize, &bitpos, |
| &offset, &mode, &unsignedp, &reversep, |
| &volatilep); |
| /* If the reference was to a (constant) zero offset, we can use |
| the address of the base if it has the same base type |
| as the result type and the pointer type is unqualified. */ |
| if (!offset |
| && known_eq (bitpos, 0) |
| && (TYPE_MAIN_VARIANT (TREE_TYPE (type)) |
| == TYPE_MAIN_VARIANT (TREE_TYPE (base))) |
| && TYPE_QUALS (type) == TYPE_UNQUALIFIED) |
| return fold_convert_loc (loc, type, |
| build_fold_addr_expr_loc (loc, base)); |
| } |
| |
| if (TREE_CODE (op0) == MODIFY_EXPR |
| && TREE_CONSTANT (TREE_OPERAND (op0, 1)) |
| /* Detect assigning a bitfield. */ |
| && !(TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF |
| && DECL_BIT_FIELD |
| (TREE_OPERAND (TREE_OPERAND (op0, 0), 1)))) |
| { |
| /* Don't leave an assignment inside a conversion |
| unless assigning a bitfield. */ |
| tem = fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 1)); |
| /* First do the assignment, then return converted constant. */ |
| tem = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (tem), op0, tem); |
| suppress_warning (tem /* What warning? */); |
| TREE_USED (tem) = 1; |
| return tem; |
| } |
| |
| /* Convert (T)(x & c) into (T)x & (T)c, if c is an integer |
| constants (if x has signed type, the sign bit cannot be set |
| in c). This folds extension into the BIT_AND_EXPR. |
| ??? We don't do it for BOOLEAN_TYPE or ENUMERAL_TYPE because they |
| very likely don't have maximal range for their precision and this |
| transformation effectively doesn't preserve non-maximal ranges. */ |
| if (TREE_CODE (type) == INTEGER_TYPE |
| && TREE_CODE (op0) == BIT_AND_EXPR |
| && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST) |
| { |
| tree and_expr = op0; |
| tree and0 = TREE_OPERAND (and_expr, 0); |
| tree and1 = TREE_OPERAND (and_expr, 1); |
| int change = 0; |
| |
| if (TYPE_UNSIGNED (TREE_TYPE (and_expr)) |
| || (TYPE_PRECISION (type) |
| <= TYPE_PRECISION (TREE_TYPE (and_expr)))) |
| change = 1; |
| else if (TYPE_PRECISION (TREE_TYPE (and1)) |
| <= HOST_BITS_PER_WIDE_INT |
| && tree_fits_uhwi_p (and1)) |
| { |
| unsigned HOST_WIDE_INT cst; |
| |
| cst = tree_to_uhwi (and1); |
| cst &= HOST_WIDE_INT_M1U |
| << (TYPE_PRECISION (TREE_TYPE (and1)) - 1); |
| change = (cst == 0); |
| if (change |
| && !flag_syntax_only |
| && (load_extend_op (TYPE_MODE (TREE_TYPE (and0))) |
| == ZERO_EXTEND)) |
| { |
| tree uns = unsigned_type_for (TREE_TYPE (and0)); |
| and0 = fold_convert_loc (loc, uns, and0); |
| and1 = fold_convert_loc (loc, uns, and1); |
| } |
| } |
| if (change) |
| { |
| tem = force_fit_type (type, wi::to_widest (and1), 0, |
| TREE_OVERFLOW (and1)); |
| return fold_build2_loc (loc, BIT_AND_EXPR, type, |
| fold_convert_loc (loc, type, and0), tem); |
| } |
| } |
| |
| /* Convert (T1)(X p+ Y) into ((T1)X p+ Y), for pointer type, when the new |
| cast (T1)X will fold away. We assume that this happens when X itself |
| is a cast. */ |
| if (POINTER_TYPE_P (type) |
| && TREE_CODE (arg0) == POINTER_PLUS_EXPR |
| && CONVERT_EXPR_P (TREE_OPERAND (arg0, 0))) |
| { |
| tree arg00 = TREE_OPERAND (arg0, 0); |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| |
| /* If -fsanitize=alignment, avoid this optimization in GENERIC |
| when the pointed type needs higher alignment than |
| the p+ first operand's pointed type. */ |
| if (!in_gimple_form |
| && sanitize_flags_p (SANITIZE_ALIGNMENT) |
| && (min_align_of_type (TREE_TYPE (type)) |
| > min_align_of_type (TREE_TYPE (TREE_TYPE (arg00))))) |
| return NULL_TREE; |
| |
| arg00 = fold_convert_loc (loc, type, arg00); |
| return fold_build_pointer_plus_loc (loc, arg00, arg01); |
| } |
| |
| /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types |
| of the same precision, and X is an integer type not narrower than |
| types T1 or T2, i.e. the cast (T2)X isn't an extension. */ |
| if (INTEGRAL_TYPE_P (type) |
| && TREE_CODE (op0) == BIT_NOT_EXPR |
| && INTEGRAL_TYPE_P (TREE_TYPE (op0)) |
| && CONVERT_EXPR_P (TREE_OPERAND (op0, 0)) |
| && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op0))) |
| { |
| tem = TREE_OPERAND (TREE_OPERAND (op0, 0), 0); |
| if (INTEGRAL_TYPE_P (TREE_TYPE (tem)) |
| && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (tem))) |
| return fold_build1_loc (loc, BIT_NOT_EXPR, type, |
| fold_convert_loc (loc, type, tem)); |
| } |
| |
| /* Convert (T1)(X * Y) into (T1)X * (T1)Y if T1 is narrower than the |
| type of X and Y (integer types only). */ |
| if (INTEGRAL_TYPE_P (type) |
| && TREE_CODE (op0) == MULT_EXPR |
| && INTEGRAL_TYPE_P (TREE_TYPE (op0)) |
| && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (op0))) |
| { |
| /* Be careful not to introduce new overflows. */ |
| tree mult_type; |
| if (TYPE_OVERFLOW_WRAPS (type)) |
| mult_type = type; |
| else |
| mult_type = unsigned_type_for (type); |
| |
| if (TYPE_PRECISION (mult_type) < TYPE_PRECISION (TREE_TYPE (op0))) |
| { |
| tem = fold_build2_loc (loc, MULT_EXPR, mult_type, |
| fold_convert_loc (loc, mult_type, |
| TREE_OPERAND (op0, 0)), |
| fold_convert_loc (loc, mult_type, |
| TREE_OPERAND (op0, 1))); |
| return fold_convert_loc (loc, type, tem); |
| } |
| } |
| |
| return NULL_TREE; |
| |
| case VIEW_CONVERT_EXPR: |
| if (TREE_CODE (op0) == MEM_REF) |
| { |
| if (TYPE_ALIGN (TREE_TYPE (op0)) != TYPE_ALIGN (type)) |
| type = build_aligned_type (type, TYPE_ALIGN (TREE_TYPE (op0))); |
| tem = fold_build2_loc (loc, MEM_REF, type, |
| TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1)); |
| REF_REVERSE_STORAGE_ORDER (tem) = REF_REVERSE_STORAGE_ORDER (op0); |
| return tem; |
| } |
| |
| return NULL_TREE; |
| |
| case NEGATE_EXPR: |
| tem = fold_negate_expr (loc, arg0); |
| if (tem) |
| return fold_convert_loc (loc, type, tem); |
| return NULL_TREE; |
| |
| case ABS_EXPR: |
| /* Convert fabs((double)float) into (double)fabsf(float). */ |
| if (TREE_CODE (arg0) == NOP_EXPR |
| && TREE_CODE (type) == REAL_TYPE) |
| { |
| tree targ0 = strip_float_extensions (arg0); |
| if (targ0 != arg0) |
| return fold_convert_loc (loc, type, |
| fold_build1_loc (loc, ABS_EXPR, |
| TREE_TYPE (targ0), |
| targ0)); |
| } |
| return NULL_TREE; |
| |
| case BIT_NOT_EXPR: |
| /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify. */ |
| 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))); |
| 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, 1))))) |
| return fold_build2_loc (loc, BIT_XOR_EXPR, type, |
| fold_convert_loc (loc, type, |
| TREE_OPERAND (arg0, 0)), tem); |
| |
| return NULL_TREE; |
| |
| case TRUTH_NOT_EXPR: |
| /* Note that the operand of this must be an int |
| and its values must be 0 or 1. |
| ("true" is a fixed value perhaps depending on the language, |
| but we don't handle values other than 1 correctly yet.) */ |
| tem = fold_truth_not_expr (loc, arg0); |
| if (!tem) |
| return NULL_TREE; |
| return fold_convert_loc (loc, type, tem); |
| |
| case INDIRECT_REF: |
| /* Fold *&X to X if X is an lvalue. */ |
| if (TREE_CODE (op0) == ADDR_EXPR) |
| { |
| tree op00 = TREE_OPERAND (op0, 0); |
| if ((VAR_P (op00) |
| || TREE_CODE (op00) == PARM_DECL |
| || TREE_CODE (op00) == RESULT_DECL) |
| && !TREE_READONLY (op00)) |
| return op00; |
| } |
| return NULL_TREE; |
| |
| default: |
| return NULL_TREE; |
| } /* switch (code) */ |
| } |
| |
| |
| /* If the operation was a conversion do _not_ mark a resulting constant |
| with TREE_OVERFLOW if the original constant was not. These conversions |
| have implementation defined behavior and retaining the TREE_OVERFLOW |
| flag here would confuse later passes such as VRP. */ |
| tree |
| fold_unary_ignore_overflow_loc (location_t loc, enum tree_code code, |
| tree type, tree op0) |
| { |
| tree res = fold_unary_loc (loc, code, type, op0); |
| if (res |
| && TREE_CODE (res) == INTEGER_CST |
| && TREE_CODE (op0) == INTEGER_CST |
| && CONVERT_EXPR_CODE_P (code)) |
| TREE_OVERFLOW (res) = TREE_OVERFLOW (op0); |
| |
| return res; |
| } |
| |
| /* Fold a binary bitwise/truth expression of code CODE and type TYPE with |
| operands OP0 and OP1. LOC is the location of the resulting expression. |
| ARG0 and ARG1 are the NOP_STRIPed results of OP0 and OP1. |
| Return the folded expression if folding is successful. Otherwise, |
| return NULL_TREE. */ |
| static tree |
| fold_truth_andor (location_t loc, enum tree_code code, tree type, |
| tree arg0, tree arg1, tree op0, tree op1) |
| { |
| tree tem; |
| |
| /* We only do these simplifications if we are optimizing. */ |
| if (!optimize) |
| return NULL_TREE; |
| |
| /* Check for things like (A || B) && (A || C). We can convert this |
| to A || (B && C). Note that either operator can be any of the four |
| truth and/or operations and the transformation will still be |
| valid. Also note that we only care about order for the |
| ANDIF and ORIF operators. If B contains side effects, this |
| might change the truth-value of A. */ |
| if (TREE_CODE (arg0) == TREE_CODE (arg1) |
| && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR |
| || TREE_CODE (arg0) == TRUTH_ORIF_EXPR |
| || TREE_CODE (arg0) == TRUTH_AND_EXPR |
| || TREE_CODE (arg0) == TRUTH_OR_EXPR) |
| && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1))) |
| { |
| tree a00 = TREE_OPERAND (arg0, 0); |
| tree a01 = TREE_OPERAND (arg0, 1); |
| tree a10 = TREE_OPERAND (arg1, 0); |
| tree a11 = TREE_OPERAND (arg1, 1); |
| int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR |
| || TREE_CODE (arg0) == TRUTH_AND_EXPR) |
| && (code == TRUTH_AND_EXPR |
| || code == TRUTH_OR_EXPR)); |
| |
| if (operand_equal_p (a00, a10, 0)) |
| return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, |
| fold_build2_loc (loc, code, type, a01, a11)); |
| else if (commutative && operand_equal_p (a00, a11, 0)) |
| return fold_build2_loc (loc, TREE_CODE (arg0), type, a00, |
| fold_build2_loc (loc, code, type, a01, a10)); |
| else if (commutative && operand_equal_p (a01, a10, 0)) |
| return fold_build2_loc (loc, TREE_CODE (arg0), type, a01, |
| fold_build2_loc (loc, code, type, a00, a11)); |
| |
| /* This case if tricky because we must either have commutative |
| operators or else A10 must not have side-effects. */ |
| |
| else if ((commutative || ! TREE_SIDE_EFFECTS (a10)) |
| && operand_equal_p (a01, a11, 0)) |
| return fold_build2_loc (loc, TREE_CODE (arg0), type, |
| fold_build2_loc (loc, code, type, a00, a10), |
| a01); |
| } |
| |
| /* See if we can build a range comparison. */ |
| if ((tem = fold_range_test (loc, code, type, op0, op1)) != 0) |
| return tem; |
| |
| if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg0) == TRUTH_ORIF_EXPR) |
| || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg0) == TRUTH_ANDIF_EXPR)) |
| { |
| tem = merge_truthop_with_opposite_arm (loc, arg0, arg1, true); |
| if (tem) |
| return fold_build2_loc (loc, code, type, tem, arg1); |
| } |
| |
| if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg1) == TRUTH_ORIF_EXPR) |
| || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg1) == TRUTH_ANDIF_EXPR)) |
| { |
| tem = merge_truthop_with_opposite_arm (loc, arg1, arg0, false); |
| if (tem) |
| return fold_build2_loc (loc, code, type, arg0, tem); |
| } |
| |
| /* Check for the possibility of merging component references. If our |
| lhs is another similar operation, try to merge its rhs with our |
| rhs. Then try to merge our lhs and rhs. */ |
| if (TREE_CODE (arg0) == code |
| && (tem = fold_truth_andor_1 (loc, code, type, |
| TREE_OPERAND (arg0, 1), arg1)) != 0) |
| return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem); |
| |
| if ((tem = fold_truth_andor_1 (loc, code, type, arg0, arg1)) != 0) |
| return tem; |
| |
| bool logical_op_non_short_circuit = LOGICAL_OP_NON_SHORT_CIRCUIT; |
| if (param_logical_op_non_short_circuit != -1) |
| logical_op_non_short_circuit |
| = param_logical_op_non_short_circuit; |
| if (logical_op_non_short_circuit |
| && !sanitize_coverage_p () |
| && (code == TRUTH_AND_EXPR |
| || code == TRUTH_ANDIF_EXPR |
| || code == TRUTH_OR_EXPR |
| || code == TRUTH_ORIF_EXPR)) |
| { |
| enum tree_code ncode, icode; |
| |
| ncode = (code == TRUTH_ANDIF_EXPR || code == TRUTH_AND_EXPR) |
| ? TRUTH_AND_EXPR : TRUTH_OR_EXPR; |
| icode = ncode == TRUTH_AND_EXPR ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; |
| |
| /* Transform ((A AND-IF B) AND[-IF] C) into (A AND-IF (B AND C)), |
| or ((A OR-IF B) OR[-IF] C) into (A OR-IF (B OR C)) |
| We don't want to pack more than two leafs to a non-IF AND/OR |
| expression. |
| If tree-code of left-hand operand isn't an AND/OR-IF code and not |
| equal to IF-CODE, then we don't want to add right-hand operand. |
| If the inner right-hand side of left-hand operand has |
| side-effects, or isn't simple, then we can't add to it, |
| as otherwise we might destroy if-sequence. */ |
| if (TREE_CODE (arg0) == icode |
| && simple_operand_p_2 (arg1) |
| /* Needed for sequence points to handle trappings, and |
| side-effects. */ |
| && simple_operand_p_2 (TREE_OPERAND (arg0, 1))) |
| { |
| tem = fold_build2_loc (loc, ncode, type, TREE_OPERAND (arg0, 1), |
| arg1); |
| return fold_build2_loc (loc, icode, type, TREE_OPERAND (arg0, 0), |
| tem); |
| } |
| /* Same as above but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C), |
| or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C). */ |
| else if (TREE_CODE (arg1) == icode |
| && simple_operand_p_2 (arg0) |
| /* Needed for sequence points to handle trappings, and |
| side-effects. */ |
| && simple_operand_p_2 (TREE_OPERAND (arg1, 0))) |
| { |
| tem = fold_build2_loc (loc, ncode, type, |
| arg0, TREE_OPERAND (arg1, 0)); |
| return fold_build2_loc (loc, icode, type, tem, |
| TREE_OPERAND (arg1, 1)); |
| } |
| /* Transform (A AND-IF B) into (A AND B), or (A OR-IF B) |
| into (A OR B). |
| For sequence point consistancy, we need to check for trapping, |
| and side-effects. */ |
| else if (code == icode && simple_operand_p_2 (arg0) |
| && simple_operand_p_2 (arg1)) |
| return fold_build2_loc (loc, ncode, type, arg0, arg1); |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* Helper that tries to canonicalize the comparison ARG0 CODE ARG1 |
| by changing CODE to reduce the magnitude of constants involved in |
| ARG0 of the comparison. |
| Returns a canonicalized comparison tree if a simplification was |
| possible, otherwise returns NULL_TREE. |
| Set *STRICT_OVERFLOW_P to true if the canonicalization is only |
| valid if signed overflow is undefined. */ |
| |
| static tree |
| maybe_canonicalize_comparison_1 (location_t loc, enum tree_code code, tree type, |
| tree arg0, tree arg1, |
| bool *strict_overflow_p) |
| { |
| enum tree_code code0 = TREE_CODE (arg0); |
| tree t, cst0 = NULL_TREE; |
| int sgn0; |
| |
| /* 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. */ |
| cst0 = TREE_OPERAND (arg0, 1); |
| sgn0 = tree_int_cst_sgn (cst0); |
| |
| /* Overflowed constants and zero will cause problems. */ |
| if (integer_zerop (cst0) |
| || TREE_OVERFLOW (cst0)) |
| return NULL_TREE; |
| |
| /* See if we can reduce the magnitude of the constant in |
| arg0 by changing the comparison code. */ |
| /* 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; |
| |
| /* Now build the constant reduced in magnitude. But not if that |
| would produce one outside of its types range. */ |
| if (INTEGRAL_TYPE_P (TREE_TYPE (cst0)) |
| && ((sgn0 == 1 |
| && TYPE_MIN_VALUE (TREE_TYPE (cst0)) |
| && tree_int_cst_equal (cst0, TYPE_MIN_VALUE (TREE_TYPE (cst0)))) |
| || (sgn0 == -1 |
| && TYPE_MAX_VALUE (TREE_TYPE (cst0)) |
| && tree_int_cst_equal (cst0, TYPE_MAX_VALUE (TREE_TYPE (cst0)))))) |
| return NULL_TREE; |
| |
| t = int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR, |
| cst0, build_int_cst (TREE_TYPE (cst0), 1)); |
| t = fold_build2_loc (loc, code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t); |
| t = fold_convert (TREE_TYPE (arg1), t); |
| |
| return fold_build2_loc (loc, code, type, t, arg1); |
| } |
| |
| /* Canonicalize the comparison ARG0 CODE ARG1 with type TYPE with undefined |
| overflow further. Try to decrease the magnitude of constants involved |
| by changing LE_EXPR and GE_EXPR to LT_EXPR and GT_EXPR or vice versa |
| and put sole constants at the second argument position. |
| Returns the canonicalized tree if changed, otherwise NULL_TREE. */ |
| |
| static tree |
| maybe_canonicalize_comparison (location_t loc, enum tree_code code, tree type, |
| tree arg0, tree arg1) |
| { |
| tree t; |
| bool strict_overflow_p; |
| const char * const warnmsg = G_("assuming signed overflow does not occur " |
| "when reducing constant in comparison"); |
| |
| /* Try canonicalization by simplifying arg0. */ |
| strict_overflow_p = false; |
| t = maybe_canonicalize_comparison_1 (loc, code, type, arg0, arg1, |
| &strict_overflow_p); |
| if (t) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE); |
| return t; |
| } |
| |
| /* Try canonicalization by simplifying arg1 using the swapped |
| comparison. */ |
| code = swap_tree_comparison (code); |
| strict_overflow_p = false; |
| t = maybe_canonicalize_comparison_1 (loc, code, type, arg1, arg0, |
| &strict_overflow_p); |
| if (t && strict_overflow_p) |
| fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE); |
| return t; |
| } |
| |
| /* Return whether BASE + OFFSET + BITPOS may wrap around the address |
| space. This is used to avoid issuing overflow warnings for |
| expressions like &p->x which cannot wrap. */ |
| |
| static bool |
| pointer_may_wrap_p (tree base, tree offset, poly_int64 bitpos) |
| { |
| if (!POINTER_TYPE_P (TREE_TYPE (base))) |
| return true; |
| |
| if (maybe_lt (bitpos, 0)) |
| return true; |
| |
| poly_wide_int wi_offset; |
| int precision = TYPE_PRECISION (TREE_TYPE (base)); |
| if (offset == NULL_TREE) |
| wi_offset = wi::zero (precision); |
| else if (!poly_int_tree_p (offset) || TREE_OVERFLOW (offset)) |
| return true; |
| else |
| wi_offset = wi::to_poly_wide (offset); |
| |
| wi::overflow_type overflow; |
| poly_wide_int units = wi::shwi (bits_to_bytes_round_down (bitpos), |
| precision); |
| poly_wide_int total = wi::add (wi_offset, units, UNSIGNED, &overflow); |
| if (overflow) |
| return true; |
| |
| poly_uint64 total_hwi, size; |
| if (!total.to_uhwi (&total_hwi) |
| || !poly_int_tree_p (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (base))), |
| &size) |
| || known_eq (size, 0U)) |
| return true; |
| |
| if (known_le (total_hwi, size)) |
| return false; |
| |
| /* We can do slightly better for SIZE if we have an ADDR_EXPR of an |
| array. */ |
| if (TREE_CODE (base) == ADDR_EXPR |
| && poly_int_tree_p (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (base, 0))), |
| &size) |
| && maybe_ne (size, 0U) |
| && known_le (total_hwi, size)) |
| return false; |
| |
| return true; |
| } |
| |
| /* Return a positive integer when the symbol DECL is known to have |
| a nonzero address, zero when it's known not to (e.g., it's a weak |
| symbol), and a negative integer when the symbol is not yet in the |
| symbol table and so whether or not its address is zero is unknown. |
| For function local objects always return positive integer. */ |
| static int |
| maybe_nonzero_address (tree decl) |
| { |
| if (DECL_P (decl) && decl_in_symtab_p (decl)) |
| if (struct symtab_node *symbol = symtab_node::get_create (decl)) |
| return symbol->nonzero_address (); |
| |
| /* Function local objects are never NULL. */ |
| if (DECL_P (decl) |
| && (DECL_CONTEXT (decl) |
| && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL |
| && auto_var_in_fn_p (decl, DECL_CONTEXT (decl)))) |
| return 1; |
| |
| return -1; |
| } |
| |
| /* Subroutine of fold_binary. This routine performs all of the |
| transformations that are common to the equality/inequality |
| operators (EQ_EXPR and NE_EXPR) and the ordering operators |
| (LT_EXPR, LE_EXPR, GE_EXPR and GT_EXPR). Callers other than |
| fold_binary should call fold_binary. Fold a comparison with |
| tree code CODE and type TYPE with operands OP0 and OP1. Return |
| the folded comparison or NULL_TREE. */ |
| |
| static tree |
| fold_comparison (location_t loc, enum tree_code code, tree type, |
| tree op0, tree op1) |
| { |
| const bool equality_code = (code == EQ_EXPR || code == NE_EXPR); |
| tree arg0, arg1, tem; |
| |
| arg0 = op0; |
| arg1 = op1; |
| |
| STRIP_SIGN_NOPS (arg0); |
| STRIP_SIGN_NOPS (arg1); |
| |
| /* 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 |
| POINTER_PLUS_EXPR to do more than the operand_equal_p test below. */ |
| if (POINTER_TYPE_P (TREE_TYPE (arg0)) |
| && (TREE_CODE (arg0) == ADDR_EXPR |
| || TREE_CODE (arg1) == ADDR_EXPR |
| || TREE_CODE (arg0) == POINTER_PLUS_EXPR |
| || TREE_CODE (arg1) == POINTER_PLUS_EXPR)) |
| { |
| tree base0, base1, offset0 = NULL_TREE, offset1 = NULL_TREE; |
| poly_int64 bitsize, bitpos0 = 0, bitpos1 = 0; |
| machine_mode mode; |
| int volatilep, reversep, unsignedp; |
| bool indirect_base0 = false, indirect_base1 = false; |
| |
| /* Get base and offset for the access. Strip ADDR_EXPR for |
| get_inner_reference, but put it back by stripping INDIRECT_REF |
| off the base object if possible. indirect_baseN will be true |
| if baseN is not an address but refers to the object itself. */ |
| base0 = arg0; |
| if (TREE_CODE (arg0) == ADDR_EXPR) |
| { |
| base0 |
| = get_inner_reference (TREE_OPERAND (arg0, 0), |
| &bitsize, &bitpos0, &offset0, &mode, |
| &unsignedp, &reversep, &volatilep); |
| if (TREE_CODE (base0) == INDIRECT_REF) |
| base0 = TREE_OPERAND (base0, 0); |
| else |
| indirect_base0 = true; |
| } |
| else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR) |
| { |
| base0 = TREE_OPERAND (arg0, 0); |
| STRIP_SIGN_NOPS (base0); |
| if (TREE_CODE (base0) == ADDR_EXPR) |
| { |
| base0 |
| = get_inner_reference (TREE_OPERAND (base0, 0), |
| &bitsize, &bitpos0, &offset0, &mode, |
| &unsignedp, &reversep, &volatilep); |
| if (TREE_CODE (base0) == INDIRECT_REF) |
| base0 = TREE_OPERAND (base0, 0); |
| else |
| indirect_base0 = true; |
| } |
| if (offset0 == NULL_TREE || integer_zerop (offset0)) |
| offset0 = TREE_OPERAND (arg0, 1); |
| else |
| offset0 = size_binop (PLUS_EXPR, offset0, |
| TREE_OPERAND (arg0, 1)); |
| if (poly_int_tree_p (offset0)) |
| { |
| poly_offset_int tem = wi::sext (wi::to_poly_offset (offset0), |
| TYPE_PRECISION (sizetype)); |
| tem <<= LOG2_BITS_PER_UNIT; |
| tem += bitpos0; |
| if (tem.to_shwi (&bitpos0)) |
| offset0 = NULL_TREE; |
| } |
| } |
| |
| base1 = arg1; |
| if (TREE_CODE (arg1) == ADDR_EXPR) |
| { |
| base1 |
| = get_inner_reference (TREE_OPERAND (arg1, 0), |
| &bitsize, &bitpos1, &offset1, &mode, |
| &unsignedp, &reversep, &volatilep); |
| if (TREE_CODE (base1) == INDIRECT_REF) |
| base1 = TREE_OPERAND (base1, 0); |
| else |
| indirect_base1 = true; |
| } |
| else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR) |
| { |
| base1 = TREE_OPERAND (arg1, 0); |
| STRIP_SIGN_NOPS (base1); |
| if (TREE_CODE (base1) == ADDR_EXPR) |
| { |
| base1 |
| = get_inner_reference (TREE_OPERAND (base1, 0), |
| &bitsize, &bitpos1, &offset1, &mode, |
| &unsignedp, &reversep, &volatilep); |
| if (TREE_CODE (base1) == INDIRECT_REF) |
| base1 = TREE_OPERAND (base1, 0); |
| else |
| indirect_base1 = true; |
| } |
| if (offset1 == NULL_TREE || integer_zerop (offset1)) |
| offset1 = TREE_OPERAND (arg1, 1); |
| else |
| offset1 = size_binop (PLUS_EXPR, offset1, |
| TREE_OPERAND (arg1, 1)); |
| if (poly_int_tree_p (offset1)) |
| { |
| poly_offset_int tem = wi::sext (wi::to_poly_offset (offset1), |
| TYPE_PRECISION (sizetype)); |
| tem <<= LOG2_BITS_PER_UNIT; |
| tem += bitpos1; |
| if (tem.to_shwi (&bitpos1)) |
| offset1 = NULL_TREE; |
| } |
| } |
| |
| /* If we have equivalent bases we might be able to simplify. */ |
| 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. */ |
| if ((offset0 == offset1 |
| || (offset0 && offset1 |
| && operand_equal_p (offset0, offset1, 0))) |
| && (equality_code |
| || (indirect_base0 |
| && (DECL_P (base0) || CONSTANT_CLASS_P (base0))) |
| || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))) |
| { |
| if (!equality_code |
| && maybe_ne (bitpos0, bitpos1) |
| && (pointer_may_wrap_p (base0, offset0, bitpos0) |
| || pointer_may_wrap_p (base1, offset1, bitpos1))) |
| fold_overflow_warning (("assuming pointer wraparound does not " |
| "occur when comparing P +- C1 with " |
| "P +- C2"), |
| WARN_STRICT_OVERFLOW_CONDITIONAL); |
| |
| switch (code) |
| { |
| case EQ_EXPR: |
| if (known_eq (bitpos0, bitpos1)) |
| return constant_boolean_node (true, type); |
| if (known_ne (bitpos0, bitpos1)) |
| return constant_boolean_node (false, type); |
| break; |
| case NE_EXPR: |
| if (known_ne (bitpos0, bitpos1)) |
| return constant_boolean_node (true, type); |
| if (known_eq (bitpos0, bitpos1)) |
| return constant_boolean_node (false, type); |
| break; |
| case LT_EXPR: |
| if (known_lt (bitpos0, bitpos1)) |
| return constant_boolean_node (true, type); |
| if (known_ge (bitpos0, bitpos1)) |
| return constant_boolean_node (false, type); |
| break; |
| case LE_EXPR: |
| if (known_le (bitpos0, bitpos1)) |
| return constant_boolean_node (true, type); |
| if (known_gt (bitpos0, bitpos1)) |
| return constant_boolean_node (false, type); |
| break; |
| case GE_EXPR: |
| if (known_ge (bitpos0, bitpos1)) |
| return constant_boolean_node (true, type); |
| if (known_lt (bitpos0, bitpos1)) |
| return constant_boolean_node (false, type); |
| break; |
| case GT_EXPR: |
| if (known_gt (bitpos0, bitpos1)) |
| return constant_boolean_node (true, type); |
| if (known_le (bitpos0, bitpos1)) |
| return constant_boolean_node (false, type); |
| break; |
| default:; |
| } |
| } |
| /* We can simplify the comparison to a comparison of the variable |
| offset parts if the constant offset parts are equal. |
| Be careful to use signed sizetype here because otherwise we |
| mess with array offsets in the wrong way. This is possible |
| because pointer arithmetic is restricted to retain within an |
| object and overflow on pointer differences is undefined as of |
| 6.5.6/8 and /9 with respect to the signed ptrdiff_t. */ |
| else if (known_eq (bitpos0, bitpos1) |
| && (equality_code |
| || (indirect_base0 |
| && (DECL_P (base0) || CONSTANT_CLASS_P (base0))) |
| || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))) |
| { |
| /* By converting to signed sizetype we cover middle-end pointer |
| arithmetic which operates on unsigned pointer types of size |
| type size and ARRAY_REF offsets which are properly sign or |
| zero extended from their type in case it is narrower than |
| sizetype. */ |
| if (offset0 == NULL_TREE) |
| offset0 = build_int_cst (ssizetype, 0); |
| else |
| offset0 = fold_convert_loc (loc, ssizetype, offset0); |
| if (offset1 == NULL_TREE) |
| offset1 = build_int_cst (ssizetype, 0); |
| else |
| offset1 = fold_convert_loc (loc, ssizetype, offset1); |
| |
| if (!equality_code |
| && (pointer_may_wrap_p (base0, offset0, bitpos0) |
| || pointer_may_wrap_p (base1, offset1, bitpos1))) |
| fold_overflow_warning (("assuming pointer wraparound does not " |
| "occur when comparing P +- C1 with " |
| "P +- C2"), |
| WARN_STRICT_OVERFLOW_COMPARISON); |
| |
| return fold_build2_loc (loc, code, type, offset0, offset1); |
| } |
| } |
| /* For equal offsets we can simplify to a comparison of the |
| base addresses. */ |
| else if (known_eq (bitpos0, bitpos1) |
| && (indirect_base0 |
| ? base0 != TREE_OPERAND (arg0, 0) : base0 != arg0) |
| && (indirect_base1 |
| ? base1 != TREE_OPERAND (arg1, 0) : base1 != arg1) |
| && ((offset0 == offset1) |
| || (offset0 && offset1 |
| && operand_equal_p (offset0, offset1, 0)))) |
| { |
| if (indirect_base0) |
| base0 = build_fold_addr_expr_loc (loc, base0); |
| if (indirect_base1) |
| base1 = build_fold_addr_expr_loc (loc, base1); |
| return fold_build2_loc (loc, code, type, base0, base1); |
| } |
| /* Comparison between an ordinary (non-weak) symbol and a null |
| pointer can be eliminated since such symbols must have a non |
| null address. In C, relational expressions between pointers |
| to objects and null pointers are undefined. The results |
| below follow the C++ rules with the additional property that |
| every object pointer compares greater than a null pointer. |
| */ |
| else if (((DECL_P (base0) |
| && maybe_nonzero_address (base0) > 0 |
| /* Avoid folding references to struct members at offset 0 to |
| prevent tests like '&ptr->firstmember == 0' from getting |
| eliminated. When ptr is null, although the -> expression |
| is strictly speaking invalid, GCC retains it as a matter |
| of QoI. See PR c/44555. */ |
| && (offset0 == NULL_TREE && known_ne (bitpos0, 0))) |
| || CONSTANT_CLASS_P (base0)) |
| && indirect_base0 |
| /* The caller guarantees that when one of the arguments is |
| constant (i.e., null in this case) it is second. */ |
| && integer_zerop (arg1)) |
| { |
| switch (code) |
| { |
| case EQ_EXPR: |
| case LE_EXPR: |
| case LT_EXPR: |
| return constant_boolean_node (false, type); |
| case GE_EXPR: |
| case GT_EXPR: |
| case NE_EXPR: |
| return constant_boolean_node (true, type); |
| default: |
| gcc_unreachable (); |
| } |
| } |
| } |
| |
| /* Transform comparisons of the form X +- C1 CMP Y +- C2 to |
| 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 (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))) |
| && (TREE_CODE (arg1) == PLUS_EXPR || TREE_CODE (arg1) == MINUS_EXPR) |
| && (TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST |
| && !TREE_OVERFLOW (TREE_OPERAND (arg1, 1)))) |
| { |
| tree const1 = TREE_OPERAND (arg0, 1); |
| tree const2 = TREE_OPERAND (arg1, 1); |
| tree variable1 = TREE_OPERAND (arg0, 0); |
| tree variable2 = TREE_OPERAND (arg1, 0); |
| tree cst; |
| const char * const warnmsg = G_("assuming signed overflow does not " |
| "occur when combining constants around " |
| "a comparison"); |
| |
| /* Put the constant on the side where it doesn't overflow and is |
| of lower absolute value and of same sign than before. */ |
| cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1) |
| ? MINUS_EXPR : PLUS_EXPR, |
| const2, const1); |
| if (!TREE_OVERFLOW (cst) |
| && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2) |
| && tree_int_cst_sgn (cst) == tree_int_cst_sgn (const2)) |
| { |
| fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); |
| return fold_build2_loc (loc, code, type, |
| variable1, |
| fold_build2_loc (loc, TREE_CODE (arg1), |
| TREE_TYPE (arg1), |
| variable2, cst)); |
| } |
| |
| cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1) |
| ? MINUS_EXPR : PLUS_EXPR, |
| const1, const2); |
| if (!TREE_OVERFLOW (cst) |
| && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1) |
| && tree_int_cst_sgn (cst) == tree_int_cst_sgn (const1)) |
| { |
| fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); |
| return fold_build2_loc (loc, code, type, |
| fold_build2_loc (loc, TREE_CODE (arg0), |
| TREE_TYPE (arg0), |
| variable1, cst), |
| variable2); |
| } |
| } |
| |
| tem = maybe_canonicalize_comparison (loc, code, type, arg0, arg1); |
| if (tem) |
| return tem; |
| |
| /* 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 |
| to check: the two values can either be equal, the first can be |
| greater, or the second can be greater. Fold the expression for |
| those three values. Since each value must be 0 or 1, we have |
| eight possibilities, each of which corresponds to the constant 0 |
| or 1 or one of the six possible comparisons. |
| |
| This handles common cases like (a > b) == 0 but also handles |
| expressions like ((x > y) - (y > x)) > 0, which supposedly |
| occur in macroized code. */ |
| |
| if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST) |
| { |
| tree cval1 = 0, cval2 = 0; |
| |
| if (twoval_comparison_p (arg0, &cval1, &cval2) |
| /* Don't handle degenerate cases here; they should already |
| have been handled anyway. */ |
| && cval1 != 0 && cval2 != 0 |
| && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2)) |
| && TREE_TYPE (cval1) == TREE_TYPE (cval2) |
| && INTEGRAL_TYPE_P (TREE_TYPE (cval1)) |
| && TYPE_MAX_VALUE (TREE_TYPE (cval1)) |
| && TYPE_MAX_VALUE (TREE_TYPE (cval2)) |
| && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)), |
| TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0)) |
| { |
| tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1)); |
| tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1)); |
| |
| /* We can't just pass T to eval_subst in case cval1 or cval2 |
| was the same as ARG1. */ |
| |
| tree high_result |
| = fold_build2_loc (loc, code, type, |
| eval_subst (loc, arg0, cval1, maxval, |
| cval2, minval), |
| arg1); |
| tree equal_result |
| = fold_build2_loc (loc, code, type, |
| eval_subst (loc, arg0, cval1, maxval, |
| cval2, maxval), |
| arg1); |
| tree low_result |
| = fold_build2_loc (loc, code, type, |
| eval_subst (loc, arg0, cval1, minval, |
| cval2, maxval), |
| arg1); |
| |
| /* All three of these results should be 0 or 1. Confirm they are. |
| Then use those values to select the proper code to use. */ |
| |
| if (TREE_CODE (high_result) == INTEGER_CST |
| && TREE_CODE (equal_result) == INTEGER_CST |
| && TREE_CODE (low_result) == INTEGER_CST) |
| { |
| /* Make a 3-bit mask with the high-order bit being the |
| value for `>', the next for '=', and the low for '<'. */ |
| switch ((integer_onep (high_result) * 4) |
| + (integer_onep (equal_result) * 2) |
| + integer_onep (low_result)) |
| { |
| case 0: |
| /* Always false. */ |
| return omit_one_operand_loc (loc, type, integer_zero_node, arg0); |
| case 1: |
| code = LT_EXPR; |
| break; |
| case 2: |
| code = EQ_EXPR; |
| break; |
| case 3: |
| code = LE_EXPR; |
| break; |
| case 4: |
| code = GT_EXPR; |
| break; |
| case 5: |
| code = NE_EXPR; |
| break; |
| case 6: |
| code = GE_EXPR; |
| break; |
| case 7: |
| /* Always true. */ |
| return omit_one_operand_loc (loc, type, integer_one_node, arg0); |
| } |
| |
| return fold_build2_loc (loc, code, type, cval1, cval2); |
| } |
| } |
| } |
| |
| return NULL_TREE; |
| } |
| |
| |
| /* Subroutine of fold_binary. Optimize complex multiplications of the |
| form z * conj(z), as pow(realpart(z),2) + pow(imagpart(z),2). The |
| argument EXPR represents the expression "z" of type TYPE. */ |
| |
| static tree |
| fold_mult_zconjz (location_t loc, tree type, tree expr) |
| { |
| tree itype = TREE_TYPE (type); |
| tree rpart, ipart, tem; |
| |
| if (TREE_CODE (expr) == COMPLEX_EXPR) |
| { |
| rpart = TREE_OPERAND (expr, 0); |
| ipart = TREE_OPERAND (expr, 1); |
| } |
| else if (TREE_CODE (expr) == COMPLEX_CST) |
| { |
| rpart = TREE_REALPART (expr); |
| ipart = TREE_IMAGPART (expr); |
| } |
| else |
| { |
| expr = save_expr (expr); |
| rpart = fold_build1_loc (loc, REALPART_EXPR, itype, expr); |
| ipart = fold_build1_loc (loc, IMAGPART_EXPR, itype, expr); |
| } |
| |
| rpart = save_expr (rpart); |
| ipart = save_expr (ipart); |
| tem = fold_build2_loc (loc, PLUS_EXPR, itype, |
| fold_build2_loc (loc, MULT_EXPR, itype, rpart, rpart), |
| fold_build2_loc (loc, MULT_EXPR, itype, ipart, ipart)); |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, tem, |
| build_zero_cst (itype)); |
| } |
| |
| |
| /* Helper function for fold_vec_perm. Store elements of VECTOR_CST or |
| CONSTRUCTOR ARG into array ELTS, which has NELTS elements, and return |
| true if successful. */ |
| |
| static bool |
| vec_cst_ctor_to_array (tree arg, unsigned int nelts, tree *elts) |
| { |
| unsigned HOST_WIDE_INT i, nunits; |
| |
| if (TREE_CODE (arg) == VECTOR_CST |
| && VECTOR_CST_NELTS (arg).is_constant (&nunits)) |
| { |
| for (i = 0; i < nunits; ++i) |
| elts[i] = VECTOR_CST_ELT (arg, i); |
| } |
| else if (TREE_CODE (arg) == CONSTRUCTOR) |
| { |
| constructor_elt *elt; |
| |
| FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (arg), i, elt) |
| if (i >= nelts || TREE_CODE (TREE_TYPE (elt->value)) == VECTOR_TYPE) |
| return false; |
| else |
| elts[i] = elt->value; |
| } |
| else |
| return false; |
| for (; i < nelts; i++) |
| elts[i] |
| = fold_convert (TREE_TYPE (TREE_TYPE (arg)), integer_zero_node); |
| return true; |
| } |
| |
| /* Attempt to fold vector permutation of ARG0 and ARG1 vectors using SEL |
| selector. Return the folded VECTOR_CST or CONSTRUCTOR if successful, |
| NULL_TREE otherwise. */ |
| |
| tree |
| fold_vec_perm (tree type, tree arg0, tree arg1, const vec_perm_indices &sel) |
| { |
| unsigned int i; |
| unsigned HOST_WIDE_INT nelts; |
| bool need_ctor = false; |
| |
| if (!sel.length ().is_constant (&nelts)) |
| return NULL_TREE; |
| gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (type), nelts) |
| && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)), nelts) |
| && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)), nelts)); |
| if (TREE_TYPE (TREE_TYPE (arg0)) != TREE_TYPE (type) |
| || TREE_TYPE (TREE_TYPE (arg1)) != TREE_TYPE (type)) |
| return NULL_TREE; |
| |
| tree *in_elts = XALLOCAVEC (tree, nelts * 2); |
| if (!vec_cst_ctor_to_array (arg0, nelts, in_elts) |
| || !vec_cst_ctor_to_array (arg1, nelts, in_elts + nelts)) |
| return NULL_TREE; |
| |
| tree_vector_builder out_elts (type, nelts, 1); |
| for (i = 0; i < nelts; i++) |
| { |
| HOST_WIDE_INT index; |
| if (!sel[i].is_constant (&index)) |
| return NULL_TREE; |
| if (!CONSTANT_CLASS_P (in_elts[index])) |
| need_ctor = true; |
| out_elts.quick_push (unshare_expr (in_elts[index])); |
| } |
| |
| if (need_ctor) |
| { |
| vec<constructor_elt, va_gc> *v; |
| vec_alloc (v, nelts); |
| for (i = 0; i < nelts; i++) |
| CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, out_elts[i]); |
| return build_constructor (type, v); |
| } |
| else |
| return out_elts.build (); |
| } |
| |
| /* Try to fold a pointer difference of type TYPE two address expressions of |
| array references AREF0 and AREF1 using location LOC. Return a |
| simplified expression for the difference or NULL_TREE. */ |
| |
| static tree |
| fold_addr_of_array_ref_difference (location_t loc, tree type, |
| tree aref0, tree aref1, |
| bool use_pointer_diff) |
| { |
| tree base0 = TREE_OPERAND (aref0, 0); |
| tree base1 = TREE_OPERAND (aref1, 0); |
| tree base_offset = build_int_cst (type, 0); |
| |
| /* If the bases are array references as well, recurse. If the bases |
| are pointer indirections compute the difference of the pointers. |
| If the bases are equal, we are set. */ |
| if ((TREE_CODE (base0) == ARRAY_REF |
| && TREE_CODE (base1) == ARRAY_REF |
| && (base_offset |
| = fold_addr_of_array_ref_difference (loc, type, base0, base1, |
| use_pointer_diff))) |
| || (INDIRECT_REF_P (base0) |
| && INDIRECT_REF_P (base1) |
| && (base_offset |
| = use_pointer_diff |
| ? fold_binary_loc (loc, POINTER_DIFF_EXPR, type, |
| TREE_OPERAND (base0, 0), |
| TREE_OPERAND (base1, 0)) |
| : 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)); |
| tree esz = fold_convert_loc (loc, type, array_ref_element_size (aref0)); |
| tree diff = fold_build2_loc (loc, MINUS_EXPR, type, op0, op1); |
| return fold_build2_loc (loc, PLUS_EXPR, type, |
| base_offset, |
| fold_build2_loc (loc, MULT_EXPR, type, |
| diff, esz)); |
| } |
| return NULL_TREE; |
| } |
| |
| /* If the real or vector real constant CST of type TYPE has an exact |
| inverse, return it, else return NULL. */ |
| |
| tree |
| exact_inverse (tree type, tree cst) |
| { |
| REAL_VALUE_TYPE r; |
| tree unit_type; |
| machine_mode mode; |
| |
| switch (TREE_CODE (cst)) |
| { |
| case REAL_CST: |
| r = TREE_REAL_CST (cst); |
| |
| if (exact_real_inverse (TYPE_MODE (type), &r)) |
| return build_real (type, r); |
| |
| return NULL_TREE; |
| |
| case VECTOR_CST: |
| { |
| unit_type = TREE_TYPE (type); |
| mode = TYPE_MODE (unit_type); |
| |
| tree_vector_builder elts; |
| if (!elts.new_unary_operation (type, cst, false)) |
| return NULL_TREE; |
| unsigned int count = elts.encoded_nelts (); |
| for (unsigned int i = 0; i < count; ++i) |
| { |
| r = TREE_REAL_CST (VECTOR_CST_ELT (cst, i)); |
| if (!exact_real_inverse (mode, &r)) |
| return NULL_TREE; |
| elts.quick_push (build_real (unit_type, r)); |
| } |
| |
| return elts.build (); |
| } |
| |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| /* Mask out the tz least significant bits of X of type TYPE where |
| tz is the number of trailing zeroes in Y. */ |
| static wide_int |
| mask_with_tz (tree type, const wide_int &x, const wide_int &y) |
| { |
| int tz = wi::ctz (y); |
| if (tz > 0) |
| return wi::mask (tz, true, TYPE_PRECISION (type)) & x; |
| return x; |
| } |
| |
| /* Return true when T is an address and is known to be nonzero. |
| For floating point we further ensure that T is not denormal. |
| Similar logic is present in nonzero_address in rtlanal.h. |
| |
| 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. */ |
| |
| static bool |
| tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p) |
| { |
| tree type = TREE_TYPE (t); |
| enum tree_code code; |
| |
| /* Doing something useful for floating point would need more work. */ |
| if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) |
| return false; |
| |
| code = TREE_CODE (t); |
| switch (TREE_CODE_CLASS (code)) |
| { |
| case tcc_unary: |
| return tree_unary_nonzero_warnv_p (code, type, TREE_OPERAND (t, 0), |
| strict_overflow_p); |
| case tcc_binary: |
| case tcc_comparison: |
| return tree_binary_nonzero_warnv_p (code, type, |
| TREE_OPERAND (t, 0), |
| TREE_OPERAND (t, 1), |
| strict_overflow_p); |
| case tcc_constant: |
| case tcc_declaration: |
| case tcc_reference: |
| return tree_single_nonzero_warnv_p (t, strict_overflow_p); |
| |
| default: |
| break; |
| } |
| |
| switch (code) |
| { |
| case TRUTH_NOT_EXPR: |
| return tree_unary_nonzero_warnv_p (code, type, TREE_OPERAND (t, 0), |
| strict_overflow_p); |
| |
| case TRUTH_AND_EXPR: |
| case TRUTH_OR_EXPR: |
| case TRUTH_XOR_EXPR: |
| return tree_binary_nonzero_warnv_p (code, type, |
| TREE_OPERAND (t, 0), |
| TREE_OPERAND (t, 1), |
| strict_overflow_p); |
| |
| case COND_EXPR: |
| case CONSTRUCTOR: |
| case OBJ_TYPE_REF: |
| case ASSERT_EXPR: |
| case ADDR_EXPR: |
| case WITH_SIZE_EXPR: |
| case SSA_NAME: |
| return tree_single_nonzero_warnv_p (t, strict_overflow_p); |
| |
| case COMPOUND_EXPR: |
| case MODIFY_EXPR: |
| case BIND_EXPR: |
| return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), |
| strict_overflow_p); |
| |
| case SAVE_EXPR: |
| return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), |
| strict_overflow_p); |
| |
| case CALL_EXPR: |
| { |
| tree fndecl = get_callee_fndecl (t); |
| if (!fndecl) return false; |
| if (flag_delete_null_pointer_checks && !flag_check_new |
| && DECL_IS_OPERATOR_NEW_P (fndecl) |
| && !TREE_NOTHROW (fndecl)) |
| return true; |
| if (flag_delete_null_pointer_checks |
| && lookup_attribute ("returns_nonnull", |
| TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) |
| return true; |
| return alloca_call_p (t); |
| } |
| |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| /* Return true when T is an address and is known to be nonzero. |
| Handle warnings about undefined signed overflow. */ |
| |
| bool |
| tree_expr_nonzero_p (tree t) |
| { |
| bool ret, strict_overflow_p; |
| |
| strict_overflow_p = false; |
| ret = tree_expr_nonzero_warnv_p (t, &strict_overflow_p); |
| if (strict_overflow_p) |
| fold_overflow_warning (("assuming signed overflow does not occur when " |
| "determining that expression is always " |
| "non-zero"), |
| WARN_STRICT_OVERFLOW_MISC); |
| return ret; |
| } |
| |
| /* Return true if T is known not to be equal to an integer W. */ |
| |
| bool |
| expr_not_equal_to (tree t, const wide_int &w) |
| { |
| value_range vr; |
| switch (TREE_CODE (t)) |
| { |
| case INTEGER_CST: |
| return wi::to_wide (t) != w; |
| |
| case SSA_NAME: |
| if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
| return false; |
| |
| if (cfun) |
| get_range_query (cfun)->range_of_expr (vr, t); |
| else |
| get_global_range_query ()->range_of_expr (vr, t); |
| |
| if (!vr.undefined_p () |
| && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w))) |
| return true; |
| /* If T has some known zero bits and W has any of those bits set, |
| then T is known not to be equal to W. */ |
| if (wi::ne_p (wi::zext (wi::bit_and_not (w, get_nonzero_bits (t)), |
| TYPE_PRECISION (TREE_TYPE (t))), 0)) |
| return true; |
| return false; |
| |
| default: |
| return false; |
| } |
| } |
| |
| /* Fold a binary expression of code CODE and type TYPE with operands |
| OP0 and OP1. LOC is the location of the resulting expression. |
| Return the folded expression if folding is successful. Otherwise, |
| return NULL_TREE. */ |
| |
| tree |
| fold_binary_loc (location_t loc, enum tree_code code, tree type, |
| tree op0, tree op1) |
| { |
| enum tree_code_class kind = TREE_CODE_CLASS (code); |
| tree arg0, arg1, tem; |
| tree t1 = NULL_TREE; |
| bool strict_overflow_p; |
| unsigned int prec; |
| |
| gcc_assert (IS_EXPR_CODE_CLASS (kind) |
| && TREE_CODE_LENGTH (code) == 2 |
| && op0 != NULL_TREE |
| && op1 != NULL_TREE); |
| |
| arg0 = op0; |
| arg1 = op1; |
| |
| /* Strip any conversions that don't change the mode. This is |
| safe for every expression, except for a comparison expression |
| because its signedness is derived from its operands. So, in |
| the latter case, only strip conversions that don't change the |
| signedness. MIN_EXPR/MAX_EXPR also need signedness of arguments |
| preserved. |
| |
| Note that this is done as an internal manipulation within the |
| constant folder, in order to find the simplest representation |
| of the arguments so that their form can be studied. In any |
| cases, the appropriate type conversions should be put back in |
| the tree that will get out of the constant folder. */ |
| |
| if (kind == tcc_comparison || code == MIN_EXPR || code == MAX_EXPR) |
| { |
| STRIP_SIGN_NOPS (arg0); |
| STRIP_SIGN_NOPS (arg1); |
| } |
| else |
| { |
| STRIP_NOPS (arg0); |
| STRIP_NOPS (arg1); |
| } |
| |
| /* Note that TREE_CONSTANT isn't enough: static var addresses are |
| constant but we can't do arithmetic on them. */ |
| if (CONSTANT_CLASS_P (arg0) && CONSTANT_CLASS_P (arg1)) |
| { |
| tem = const_binop (code, type, arg0, arg1); |
| if (tem != NULL_TREE) |
| { |
| if (TREE_TYPE (tem) != type) |
| tem = fold_convert_loc (loc, type, tem); |
| return tem; |
| } |
| } |
| |
| /* If this is a commutative operation, and ARG0 is a constant, move it |
| to ARG1 to reduce the number of tests below. */ |
| if (commutative_tree_code (code) |
| && tree_swap_operands_p (arg0, arg1)) |
| return fold_build2_loc (loc, code, type, op1, op0); |
| |
| /* Likewise if this is a comparison, and ARG0 is a constant, move it |
| to ARG1 to reduce the number of tests below. */ |
| if (kind == tcc_comparison |
| && tree_swap_operands_p (arg0, arg1)) |
| return fold_build2_loc (loc, swap_tree_comparison (code), type, op1, op0); |
| |
| tem = generic_simplify (loc, code, type, op0, op1); |
| if (tem) |
| return tem; |
| |
| /* ARG0 is the first operand of EXPR, and ARG1 is the second operand. |
| |
| First check for cases where an arithmetic operation is applied to a |
| compound, conditional, or comparison operation. Push the arithmetic |
| operation inside the compound or conditional to see if any folding |
| can then be done. Convert comparison to conditional for this purpose. |
| The also optimizes non-constant cases that used to be done in |
| expand_expr. |
| |
| Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR, |
| one of the operands is a comparison and the other is a comparison, a |
| BIT_AND_EXPR with the constant 1, or a truth value. In that case, the |
| code below would make the expression more complex. Change it to a |
| TRUTH_{AND,OR}_EXPR. Likewise, convert a similar NE_EXPR to |
| TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR. */ |
| |
| if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR |
| || code == EQ_EXPR || code == NE_EXPR) |
| && !VECTOR_TYPE_P (TREE_TYPE (arg0)) |
| && ((truth_value_p (TREE_CODE (arg0)) |
| && (truth_value_p (TREE_CODE (arg1)) |
| || (TREE_CODE (arg1) == BIT_AND_EXPR |
| && integer_onep (TREE_OPERAND (arg1, 1))))) |
| || (truth_value_p (TREE_CODE (arg1)) |
| && (truth_value_p (TREE_CODE (arg0)) |
| || (TREE_CODE (arg0) == BIT_AND_EXPR |
| && integer_onep (TREE_OPERAND (arg0, 1))))))) |
| { |
| tem = fold_build2_loc (loc, code == BIT_AND_EXPR ? TRUTH_AND_EXPR |
| : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR |
| : TRUTH_XOR_EXPR, |
| boolean_type_node, |
| fold_convert_loc (loc, boolean_type_node, arg0), |
| fold_convert_loc (loc, boolean_type_node, arg1)); |
| |
| if (code == EQ_EXPR) |
| tem = invert_truthvalue_loc (loc, tem); |
| |
| return fold_convert_loc (loc, type, tem); |
| } |
| |
| if (TREE_CODE_CLASS (code) == tcc_binary |
| || TREE_CODE_CLASS (code) == tcc_comparison) |
| { |
| if (TREE_CODE (arg0) == COMPOUND_EXPR) |
| { |
| tem = fold_build2_loc (loc, code, type, |
| fold_convert_loc (loc, TREE_TYPE (op0), |
| TREE_OPERAND (arg0, 1)), op1); |
| return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), |
| tem); |
| } |
| if (TREE_CODE (arg1) == COMPOUND_EXPR) |
| { |
| tem = fold_build2_loc (loc, code, type, op0, |
| fold_convert_loc (loc, TREE_TYPE (op1), |
| TREE_OPERAND (arg1, 1))); |
| return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0), |
| tem); |
| } |
| |
| if (TREE_CODE (arg0) == COND_EXPR |
| || TREE_CODE (arg0) == VEC_COND_EXPR |
| || COMPARISON_CLASS_P (arg0)) |
| { |
| tem = fold_binary_op_with_conditional_arg (loc, code, type, op0, op1, |
| arg0, arg1, |
| /*cond_first_p=*/1); |
| if (tem != NULL_TREE) |
| return tem; |
| } |
| |
| if (TREE_CODE (arg1) == COND_EXPR |
| || TREE_CODE (arg1) == VEC_COND_EXPR |
| || COMPARISON_CLASS_P (arg1)) |
| { |
| tem = fold_binary_op_with_conditional_arg (loc, code, type, op0, op1, |
| arg1, arg0, |
| /*cond_first_p=*/0); |
| if (tem != NULL_TREE) |
| return tem; |
| } |
| } |
| |
| switch (code) |
| { |
| case MEM_REF: |
| /* MEM[&MEM[p, CST1], CST2] -> MEM[p, CST1 + CST2]. */ |
| if (TREE_CODE (arg0) == ADDR_EXPR |
| && TREE_CODE (TREE_OPERAND (arg0, 0)) == MEM_REF) |
| { |
| tree iref = TREE_OPERAND (arg0, 0); |
| return fold_build2 (MEM_REF, type, |
| TREE_OPERAND (iref, 0), |
| int_const_binop (PLUS_EXPR, arg1, |
| TREE_OPERAND (iref, 1))); |
| } |
| |
| /* MEM[&a.b, CST2] -> MEM[&a, offsetof (a, b) + CST2]. */ |
| if (TREE_CODE (arg0) == ADDR_EXPR |
| && handled_component_p (TREE_OPERAND (arg0, 0))) |
| { |
| tree base; |
| poly_int64 coffset; |
| base = get_addr_base_and_unit_offset (TREE_OPERAND (arg0, 0), |
| &coffset); |
| if (!base) |
| return NULL_TREE; |
| return fold_build2 (MEM_REF, type, |
| build1 (ADDR_EXPR, TREE_TYPE (arg0), base), |
| int_const_binop (PLUS_EXPR, arg1, |
| size_int (coffset))); |
| } |
| |
| return NULL_TREE; |
| |
| case POINTER_PLUS_EXPR: |
| /* INT +p INT -> (PTR)(INT + INT). Stripping types allows for this. */ |
| if (INTEGRAL_TYPE_P (TREE_TYPE (arg1)) |
| && INTEGRAL_TYPE_P (TREE_TYPE (arg0))) |
| return fold_convert_loc (loc, type, |
| fold_build2_loc (loc, PLUS_EXPR, sizetype, |
| fold_convert_loc (loc, sizetype, |
| arg1), |
| fold_convert_loc (loc, sizetype, |
| arg0))); |
| |
| return NULL_TREE; |
| |
| case PLUS_EXPR: |
| if (INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type)) |
| { |
| /* X + (X / CST) * -CST is X % CST. */ |
| if (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)) |
| { |
| tree cst0 = TREE_OPERAND (TREE_OPERAND (arg1, 0), 1); |
| tree cst1 = TREE_OPERAND (arg1, 1); |
| tree sum = fold_binary_loc (loc, PLUS_EXPR, TREE_TYPE (cst1), |
| cst1, cst0); |
| if (sum && integer_zerop (sum)) |
| return fold_convert_loc (loc, type, |
| fold_build2_loc (loc, TRUNC_MOD_EXPR, |
| TREE_TYPE (arg0), arg0, |
| cst0)); |
| } |
| } |
| |
| /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the same or |
| one. Make sure the type is not saturating and has the signedness of |
| the stripped operands, as fold_plusminus_mult_expr will re-associate. |
| ??? The latter condition should use TYPE_OVERFLOW_* flags instead. */ |
| if ((TREE_CODE (arg0) == MULT_EXPR |
| || TREE_CODE (arg1) == MULT_EXPR) |
| && !TYPE_SATURATING (type) |
| && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg0)) |
| && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg1)) |
| && (!FLOAT_TYPE_P (type) || flag_associative_math)) |
| { |
| tree tem = fold_plusminus_mult_expr (loc, code, type, arg0, arg1); |
| if (tem) |
| return tem; |
| } |
| |
| if (! FLOAT_TYPE_P (type)) |
| { |
| /* Reassociate (plus (plus (mult) (foo)) (mult)) as |
| (plus (plus (mult) (mult)) (foo)) so that we can |
| take advantage of the factoring cases below. */ |
| 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) |
| || ((TREE_CODE (arg1) == PLUS_EXPR |
| || TREE_CODE (arg1) == MINUS_EXPR) |
| && TREE_CODE (arg0) == MULT_EXPR))) |
| { |
| tree parg0, parg1, parg, marg; |
| enum tree_code pcode; |
| |
| if (TREE_CODE (arg1) == MULT_EXPR) |
| parg = arg0, marg = arg1; |
| else |
| parg = arg1, marg = arg0; |
| pcode = TREE_CODE (parg); |
| parg0 = TREE_OPERAND (parg, 0); |
| parg1 = TREE_OPERAND (parg, 1); |
| STRIP_NOPS (parg0); |
| STRIP_NOPS (parg1); |
| |
| if (TREE_CODE (parg0) == MULT_EXPR |
| && TREE_CODE (parg1) != MULT_EXPR) |
| return fold_build2_loc (loc, pcode, type, |
| fold_build2_loc (loc, PLUS_EXPR, type, |
| fold_convert_loc (loc, type, |
| parg0), |
| fold_convert_loc (loc, type, |
| marg)), |
| fold_convert_loc (loc, type, parg1)); |
| if (TREE_CODE (parg0) != MULT_EXPR |
| && TREE_CODE (parg1) == MULT_EXPR) |
| return |
| fold_build2_loc (loc, PLUS_EXPR, type, |
| fold_convert_loc (loc, type, parg0), |
| fold_build2_loc (loc, pcode, type, |
| fold_convert_loc (loc, type, marg), |
| fold_convert_loc (loc, type, |
| parg1))); |
| } |
| } |
| else |
| { |
| /* Fold __complex__ ( x, 0 ) + __complex__ ( 0, y ) |
| to __complex__ ( x, y ). This is not the same for SNaNs or |
| if signed zeros are involved. */ |
| if (!HONOR_SNANS (arg0) |
| && !HONOR_SIGNED_ZEROS (arg0) |
| && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0))) |
| { |
| tree rtype = TREE_TYPE (TREE_TYPE (arg0)); |
| tree arg0r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg0); |
| tree arg0i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg0); |
| bool arg0rz = false, arg0iz = false; |
| if ((arg0r && (arg0rz = real_zerop (arg0r))) |
| || (arg0i && (arg0iz = real_zerop (arg0i)))) |
| { |
| tree arg1r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg1); |
| tree arg1i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg1); |
| if (arg0rz && arg1i && real_zerop (arg1i)) |
| { |
| tree rp = arg1r ? arg1r |
| : build1 (REALPART_EXPR, rtype, arg1); |
| tree ip = arg0i ? arg0i |
| : build1 (IMAGPART_EXPR, rtype, arg0); |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); |
| } |
| else if (arg0iz && arg1r && real_zerop (arg1r)) |
| { |
| tree rp = arg0r ? arg0r |
| : build1 (REALPART_EXPR, rtype, arg0); |
| tree ip = arg1i ? arg1i |
| : build1 (IMAGPART_EXPR, rtype, arg1); |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); |
| } |
| } |
| } |
| |
| /* Convert a + (b*c + d*e) into (a + b*c) + d*e. |
| We associate floats only if the user has specified |
| -fassociative-math. */ |
| if (flag_associative_math |
| && TREE_CODE (arg1) == PLUS_EXPR |
| && TREE_CODE (arg0) != MULT_EXPR) |
| { |
| tree tree10 = TREE_OPERAND (arg1, 0); |
| tree tree11 = TREE_OPERAND (arg1, 1); |
| if (TREE_CODE (tree11) == MULT_EXPR |
| && TREE_CODE (tree10) == MULT_EXPR) |
| { |
| tree tree0; |
| tree0 = fold_build2_loc (loc, PLUS_EXPR, type, arg0, tree10); |
| return fold_build2_loc (loc, PLUS_EXPR, type, tree0, tree11); |
| } |
| } |
| /* Convert (b*c + d*e) + a into b*c + (d*e +a). |
| We associate floats only if the user has specified |
| -fassociative-math. */ |
| if (flag_associative_math |
| && TREE_CODE (arg0) == PLUS_EXPR |
| && TREE_CODE (arg1) != MULT_EXPR) |
| { |
| tree tree00 = TREE_OPERAND (arg0, 0); |
| tree tree01 = TREE_OPERAND (arg0, 1); |
| if (TREE_CODE (tree01) == MULT_EXPR |
| && TREE_CODE (tree00) == MULT_EXPR) |
| { |
| tree tree0; |
| tree0 = fold_build2_loc (loc, PLUS_EXPR, type, tree01, arg1); |
| return fold_build2_loc (loc, PLUS_EXPR, type, tree00, tree0); |
| } |
| } |
| } |
| |
| bit_rotate: |
| /* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A |
| is a rotate of A by C1 bits. */ |
| /* (A << B) + (A >> (Z - B)) if A is unsigned and Z is the size of A |
| is a rotate of A by B bits. |
| Similarly for (A << B) | (A >> (-B & C3)) where C3 is Z-1, |
| though in this case CODE must be | and not + or ^, otherwise |
| it doesn't return A when B is 0. */ |
| { |
| enum tree_code code0, code1; |
| tree rtype; |
| code0 = TREE_CODE (arg0); |
| code1 = TREE_CODE (arg1); |
| if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR) |
| || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR)) |
| && operand_equal_p (TREE_OPERAND (arg0, 0), |
| TREE_OPERAND (arg1, 0), 0) |
| && (rtype = TREE_TYPE (TREE_OPERAND (arg0, 0)), |
| TYPE_UNSIGNED (rtype)) |
| /* Only create rotates in complete modes. Other cases are not |
| expanded properly. */ |
| && (element_precision (rtype) |
| == GET_MODE_UNIT_PRECISION (TYPE_MODE (rtype)))) |
| { |
| tree tree01, tree11; |
| tree orig_tree01, orig_tree11; |
| enum tree_code code01, code11; |
| |
| tree01 = orig_tree01 = TREE_OPERAND (arg0, 1); |
| tree11 = orig_tree11 = TREE_OPERAND (arg1, 1); |
| STRIP_NOPS (tree01); |
| STRIP_NOPS (tree11); |
| code01 = TREE_CODE (tree01); |
| code11 = TREE_CODE (tree11); |
| if (code11 != MINUS_EXPR |
| && (code01 == MINUS_EXPR || code01 == BIT_AND_EXPR)) |
| { |
| std::swap (code0, code1); |
| std::swap (code01, code11); |
| std::swap (tree01, tree11); |
| std::swap (orig_tree01, orig_tree11); |
| } |
| if (code01 == INTEGER_CST |
| && code11 == INTEGER_CST |
| && (wi::to_widest (tree01) + wi::to_widest (tree11) |
| == element_precision (rtype))) |
| { |
| tem = build2_loc (loc, LROTATE_EXPR, |
| rtype, TREE_OPERAND (arg0, 0), |
| code0 == LSHIFT_EXPR |
| ? orig_tree01 : orig_tree11); |
| return fold_convert_loc (loc, type, tem); |
| } |
| else if (code11 == MINUS_EXPR) |
| { |
| tree tree110, tree111; |
| tree110 = TREE_OPERAND (tree11, 0); |
| tree111 = TREE_OPERAND (tree11, 1); |
| STRIP_NOPS (tree110); |
| STRIP_NOPS (tree111); |
| if (TREE_CODE (tree110) == INTEGER_CST |
| && compare_tree_int (tree110, |
| element_precision (rtype)) == 0 |
| && operand_equal_p (tree01, tree111, 0)) |
| { |
| tem = build2_loc (loc, (code0 == LSHIFT_EXPR |
| ? LROTATE_EXPR : RROTATE_EXPR), |
| rtype, TREE_OPERAND (arg0, 0), |
| orig_tree01); |
| return fold_convert_loc (loc, type, tem); |
| } |
| } |
| else if (code == BIT_IOR_EXPR |
| && code11 == BIT_AND_EXPR |
| && pow2p_hwi (element_precision (rtype))) |
| { |
| tree tree110, tree111; |
| tree110 = TREE_OPERAND (tree11, 0); |
| tree111 = TREE_OPERAND (tree11, 1); |
| STRIP_NOPS (tree110); |
| STRIP_NOPS (tree111); |
| if (TREE_CODE (tree110) == NEGATE_EXPR |
| && TREE_CODE (tree111) == INTEGER_CST |
| && compare_tree_int (tree111, |
| element_precision (rtype) - 1) == 0 |
| && operand_equal_p (tree01, TREE_OPERAND (tree110, 0), 0)) |
| { |
| tem = build2_loc (loc, (code0 == LSHIFT_EXPR |
| ? LROTATE_EXPR : RROTATE_EXPR), |
| rtype, TREE_OPERAND (arg0, 0), |
| orig_tree01); |
| return fold_convert_loc (loc, type, tem); |
| } |
| } |
| } |
| } |
| |
| associate: |
| /* In most languages, can't associate operations on floats through |
| parentheses. Rather than remember where the parentheses were, we |
| don't associate floats at all, unless the user has specified |
| -fassociative-math. |
| And, we need to make sure type is not saturating. */ |
| |
| if ((! FLOAT_TYPE_P (type) || flag_associative_math) |
| && !TYPE_SATURATING (type)) |
| { |
| tree var0, minus_var0, con0, minus_con0, lit0, minus_lit0; |
| tree var1, minus_var1, con1, minus_con1, lit1, minus_lit1; |
| tree atype = type; |
| bool ok = true; |
| |
| /* Split both trees into variables, constants, and literals. Then |
| associate each group together, the constants with literals, |
| then the result with variables. This increases the chances of |
| literals being recombined later and of generating relocatable |
| expressions for the sum of a constant and literal. */ |
| var0 = split_tree (arg0, type, code, |
| &minus_var0, &con0, &minus_con0, |
| &lit0, &minus_lit0, 0); |
| var1 = split_tree (arg1, type, code, |
| &minus_var1, &con1, &minus_con1, |
| &lit1, &minus_lit1, code == MINUS_EXPR); |
| |
| /* Recombine MINUS_EXPR operands by using PLUS_EXPR. */ |
| if (code == MINUS_EXPR) |
| code = PLUS_EXPR; |
| |
| /* With undefined overflow prefer doing association in a type |
| which wraps on overflow, if that is one of the operand types. */ |
| if ((POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)) |
| && !TYPE_OVERFLOW_WRAPS (type)) |
| { |
| if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) |
| && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))) |
| atype = TREE_TYPE (arg0); |
| else if (INTEGRAL_TYPE_P (TREE_TYPE (arg1)) |
| && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))) |
| atype = TREE_TYPE (arg1); |
| gcc_assert (TYPE_PRECISION (atype) == TYPE_PRECISION (type)); |
| } |
| |
| /* With undefined overflow we can only associate constants with one |
| variable, and constants whose association doesn't overflow. */ |
| if ((POINTER_TYPE_P (atype) || INTEGRAL_TYPE_P (atype)) |
| && !TYPE_OVERFLOW_WRAPS (atype)) |
| { |
| if ((var0 && var1) || (minus_var0 && minus_var1)) |
| { |
| /* ??? If split_tree would handle NEGATE_EXPR we could |
| simply reject these cases and the allowed cases would |
| be the var0/minus_var1 ones. */ |
| tree tmp0 = var0 ? var0 : minus_var0; |
| tree tmp1 = var1 ? var1 : minus_var1; |
| bool one_neg = false; |
| |
| if (TREE_CODE (tmp0) == NEGATE_EXPR) |
| { |
| 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); |
| 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 cancel out. */ |
| if (!one_neg |
| || !operand_equal_p (tmp0, tmp1, 0)) |
| ok = false; |
| } |
| else if ((var0 && minus_var1 |
| && ! operand_equal_p (var0, minus_var1, 0)) |
| || (minus_var0 && var1 |
| && ! operand_equal_p (minus_var0, var1, 0))) |
| ok = false; |
| } |
| |
| /* Only do something if we found more than two objects. Otherwise, |
| nothing has changed and we risk infinite recursion. */ |
| if (ok |
| && ((var0 != 0) + (var1 != 0) |
| + (minus_var0 != 0) + (minus_var1 != 0) |
| + (con0 != 0) + (con1 != 0) |
| + (minus_con0 != 0) + (minus_con1 != 0) |
| + (lit0 != 0) + (lit1 != 0) |
| + (minus_lit0 != 0) + (minus_lit1 != 0)) > 2) |
| { |
| var0 = associate_trees (loc, var0, var1, code, atype); |
| minus_var0 = associate_trees (loc, minus_var0, minus_var1, |
| code, atype); |
| con0 = associate_trees (loc, con0, con1, code, atype); |
| minus_con0 = associate_trees (loc, minus_con0, minus_con1, |
| code, atype); |
| lit0 = associate_trees (loc, lit0, lit1, code, atype); |
| minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1, |
| code, atype); |
| |
| if (minus_var0 && var0) |
| { |
| var0 = associate_trees (loc, var0, minus_var0, |
| MINUS_EXPR, atype); |
| minus_var0 = 0; |
| } |
| if (minus_con0 && con0) |
| { |
| con0 = associate_trees (loc, con0, minus_con0, |
| MINUS_EXPR, atype); |
| minus_con0 = 0; |
| } |
| |
| /* Preserve the MINUS_EXPR if the negative part of the literal is |
| greater than the positive part. Otherwise, the multiplicative |
| folding code (i.e extract_muldiv) may be fooled in case |
| unsigned constants are subtracted, like in the following |
| example: ((X*2 + 4) - 8U)/2. */ |
| if (minus_lit0 && lit0) |
| { |
| if (TREE_CODE (lit0) == INTEGER_CST |
| && TREE_CODE (minus_lit0) == INTEGER_CST |
| && tree_int_cst_lt (lit0, minus_lit0) |
| /* But avoid ending up with only negated parts. */ |
| && (var0 || con0)) |
| { |
| minus_lit0 = associate_trees (loc, minus_lit0, lit0, |
| MINUS_EXPR, atype); |
| lit0 = 0; |
| } |
| else |
| { |
| lit0 = associate_trees (loc, lit0, minus_lit0, |
| MINUS_EXPR, atype); |
| minus_lit0 = 0; |
| } |
| } |
| |
| /* Don't introduce overflows through reassociation. */ |
| if ((lit0 && TREE_OVERFLOW_P (lit0)) |
| || (minus_lit0 && TREE_OVERFLOW_P (minus_lit0))) |
| return NULL_TREE; |
| |
| /* Eliminate lit0 and minus_lit0 to con0 and minus_con0. */ |
| con0 = associate_trees (loc, con0, lit0, code, atype); |
| lit0 = 0; |
| minus_con0 = associate_trees (loc, minus_con0, minus_lit0, |
| code, atype); |
| minus_lit0 = 0; |
| |
| /* Eliminate minus_con0. */ |
| if (minus_con0) |
| { |
| if (con0) |
| con0 = associate_trees (loc, con0, minus_con0, |
| MINUS_EXPR, atype); |
| else if (var0) |
| var0 = associate_trees (loc, var0, minus_con0, |
| MINUS_EXPR, atype); |
| else |
| gcc_unreachable (); |
| minus_con0 = 0; |
| } |
| |
| /* Eliminate minus_var0. */ |
| if (minus_var0) |
| { |
| if (con0) |
| con0 = associate_trees (loc, con0, minus_var0, |
| MINUS_EXPR, atype); |
| else |
| gcc_unreachable (); |
| minus_var0 = 0; |
| } |
| |
| return |
| fold_convert_loc (loc, type, associate_trees (loc, var0, con0, |
| code, atype)); |
| } |
| } |
| |
| return NULL_TREE; |
| |
| case POINTER_DIFF_EXPR: |
| case MINUS_EXPR: |
| /* Fold &a[i] - &a[j] to i-j. */ |
| if (TREE_CODE (arg0) == ADDR_EXPR |
| && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF |
| && TREE_CODE (arg1) == ADDR_EXPR |
| && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF) |
| { |
| tree tem = fold_addr_of_array_ref_difference (loc, type, |
| TREE_OPERAND (arg0, 0), |
| TREE_OPERAND (arg1, 0), |
| code |
| == POINTER_DIFF_EXPR); |
| if (tem) |
| return tem; |
| } |
| |
| /* Further transformations are not for pointers. */ |
| if (code == POINTER_DIFF_EXPR) |
| return NULL_TREE; |
| |
| /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ |
| if (TREE_CODE (arg0) == NEGATE_EXPR |
| && negate_expr_p (op1) |
| /* If arg0 is e.g. unsigned int and type is int, then this could |
| introduce UB, because if A is INT_MIN at runtime, the original |
| expression can be well defined while the latter is not. |
| See PR83269. */ |
| && !(ANY_INTEGRAL_TYPE_P (type) |
| && TYPE_OVERFLOW_UNDEFINED (type) |
| && ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0)) |
| && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))) |
| return fold_build2_loc (loc, MINUS_EXPR, type, negate_expr (op1), |
| fold_convert_loc (loc, type, |
| TREE_OPERAND (arg0, 0))); |
| |
| /* Fold __complex__ ( x, 0 ) - __complex__ ( 0, y ) to |
| __complex__ ( x, -y ). This is not the same for SNaNs or if |
| signed zeros are involved. */ |
| if (!HONOR_SNANS (arg0) |
| && !HONOR_SIGNED_ZEROS (arg0) |
| && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0))) |
| { |
| tree rtype = TREE_TYPE (TREE_TYPE (arg0)); |
| tree arg0r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg0); |
| tree arg0i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg0); |
| bool arg0rz = false, arg0iz = false; |
| if ((arg0r && (arg0rz = real_zerop (arg0r))) |
| || (arg0i && (arg0iz = real_zerop (arg0i)))) |
| { |
| tree arg1r = fold_unary_loc (loc, REALPART_EXPR, rtype, arg1); |
| tree arg1i = fold_unary_loc (loc, IMAGPART_EXPR, rtype, arg1); |
| if (arg0rz && arg1i && real_zerop (arg1i)) |
| { |
| tree rp = fold_build1_loc (loc, NEGATE_EXPR, rtype, |
| arg1r ? arg1r |
| : build1 (REALPART_EXPR, rtype, arg1)); |
| tree ip = arg0i ? arg0i |
| : build1 (IMAGPART_EXPR, rtype, arg0); |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); |
| } |
| else if (arg0iz && arg1r && real_zerop (arg1r)) |
| { |
| tree rp = arg0r ? arg0r |
| : build1 (REALPART_EXPR, rtype, arg0); |
| tree ip = fold_build1_loc (loc, NEGATE_EXPR, rtype, |
| arg1i ? arg1i |
| : build1 (IMAGPART_EXPR, rtype, arg1)); |
| return fold_build2_loc (loc, COMPLEX_EXPR, type, rp, ip); |
| } |
| } |
| } |
| |
| /* A - B -> A + (-B) if B is easily negatable. */ |
| if (negate_expr_p (op1) |
| && ! TYPE_OVERFLOW_SANITIZED (type) |
| && ((FLOAT_TYPE_P (type) |
| /* Avoid this transformation if B is a positive REAL_CST. */ |
| && (TREE_CODE (op1) != REAL_CST |
| || REAL_VALUE_NEGATIVE (TREE_REAL_CST (op1)))) |
| || INTEGRAL_TYPE_P (type))) |
| return fold_build2_loc (loc, PLUS_EXPR, type, |
| fold_convert_loc (loc, type, arg0), |
| negate_expr (op1)); |
| |
| /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the same or |
| one. Make sure the type is not saturating and has the signedness of |
| the stripped operands, as fold_plusminus_mult_expr will re-associate. |
| ??? The latter condition should use TYPE_OVERFLOW_* flags instead. */ |
| if ((TREE_CODE (arg0) == MULT_EXPR |
| || TREE_CODE (arg1) == MULT_EXPR) |
| && !TYPE_SATURATING (type) |
| && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg0)) |
| && TYPE_UNSIGNED (type) == TYPE_UNSIGNED (TREE_TYPE (arg1)) |
| && (!FLOAT_TYPE_P (type) || flag_associative_math)) |
| { |
| tree tem = fold_plusminus_mult_expr (loc, code, type, arg0, arg1); |
| if (tem) |
| return tem; |
| } |
| |
| goto associate; |
| |
| case MULT_EXPR: |
| if (! FLOAT_TYPE_P (type)) |
| { |
| /* Transform x * -C into -x * C if x is easily negatable. */ |
| if (TREE_CODE (op1) == INTEGER_CST |
| && tree_int_cst_sgn (op1) == -1 |
| && negate_expr_p (op0) |
| && negate_expr_p (op1) |
| && (tem = negate_expr (op1)) != op1 |
| && ! TREE_OVERFLOW (tem)) |
| return fold_build2_loc (loc, MULT_EXPR, type, |
| fold_convert_loc (loc, type, |
| negate_expr (op0)), tem); |
| |
| strict_overflow_p = false; |
| if (TREE_CODE (arg1) == INTEGER_CST |
| && (tem = extract_muldiv (op0, arg1, code, NULL_TREE, |
| &strict_overflow_p)) != 0) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (("assuming signed overflow does not " |
| "occur when simplifying " |
| "multiplication"), |
| WARN_STRICT_OVERFLOW_MISC); |
| return fold_convert_loc (loc, type, tem); |
| } |
| |
| /* Optimize z * conj(z) for integer complex numbers. */ |
| if (TREE_CODE (arg0) == CONJ_EXPR |
| && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) |
| return fold_mult_zconjz (loc, type, arg1); |
| if (TREE_CODE (arg1) == CONJ_EXPR |
| && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) |
| return fold_mult_zconjz (loc, type, arg0); |
| } |
| else |
| { |
| /* 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 (arg0) |
| && !HONOR_SIGNED_ZEROS (arg0) |
| && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0)) |
| && TREE_CODE (arg1) == COMPLEX_CST |
| && real_zerop (TREE_REALPART (arg1))) |
| { |
| tree rtype = TREE_TYPE (TREE_TYPE (arg0)); |
| if (real_onep (TREE_IMAGPART (arg1))) |
| return |
| fold_build2_loc (loc, COMPLEX_EXPR, type, |
| negate_expr (fold_build1_loc (loc, IMAGPART_EXPR, |
| rtype, arg0)), |
| fold_build1_loc (loc, REALPART_EXPR, rtype, arg0)); |
| else if (real_minus_onep (TREE_IMAGPART (arg1))) |
| return |
| fold_build2_loc (loc, COMPLEX_EXPR, type, |
| fold_build1_loc (loc, IMAGPART_EXPR, rtype, arg0), |
| negate_expr (fold_build1_loc (loc, REALPART_EXPR, |
| rtype, arg0))); |
| } |
| |
| /* Optimize z * conj(z) for floating point complex numbers. |
| Guarded by flag_unsafe_math_optimizations as non-finite |
| imaginary components don't produce scalar results. */ |
| if (flag_unsafe_math_optimizations |
| && TREE_CODE (arg0) == CONJ_EXPR |
| && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) |
| return fold_mult_zconjz (loc, type, arg1); |
| if (flag_unsafe_math_optimizations |
| && TREE_CODE (arg1) == CONJ_EXPR |
| && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) |
| return fold_mult_zconjz (loc, type, arg0); |
| } |
| goto associate; |
| |
| case BIT_IOR_EXPR: |
| /* Canonicalize (X & C1) | C2. */ |
| if (TREE_CODE (arg0) == BIT_AND_EXPR |
| && TREE_CODE (arg1) == INTEGER_CST |
| && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) |
| { |
| int width = TYPE_PRECISION (type), w; |
| wide_int c1 = wi::to_wide (TREE_OPERAND (arg0, 1)); |
| wide_int c2 = wi::to_wide (arg1); |
| |
| /* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2). */ |
| if ((c1 & c2) == c1) |
| return omit_one_operand_loc (loc, type, arg1, |
| TREE_OPERAND (arg0, 0)); |
| |
| wide_int msk = wi::mask (width, false, |
| TYPE_PRECISION (TREE_TYPE (arg1))); |
| |
| /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */ |
| if (wi::bit_and_not (msk, c1 | c2) == 0) |
| { |
| tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); |
| return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1); |
| } |
| |
| /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2, |
| unless (C1 & ~C2) | (C2 & C3) for some C3 is a mask of some |
| mode which allows further optimizations. */ |
| c1 &= msk; |
| c2 &= msk; |
| wide_int c3 = wi::bit_and_not (c1, c2); |
| for (w = BITS_PER_UNIT; w <= width; w <<= 1) |
| { |
| wide_int mask = wi::mask (w, false, |
| TYPE_PRECISION (type)); |
| if (((c1 | c2) & mask) == mask |
| && wi::bit_and_not (c1, mask) == 0) |
| { |
| c3 = mask; |
| break; |
| } |
| } |
| |
| if (c3 != c1) |
| { |
| tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); |
| tem = fold_build2_loc (loc, BIT_AND_EXPR, type, tem, |
| wide_int_to_tree (type, c3)); |
| return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1); |
| } |
| } |
| |
| /* 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: |
| /* Fold (X & 1) ^ 1 as (X & 1) == 0. */ |
| if (TREE_CODE (arg0) == BIT_AND_EXPR |
| && INTEGRAL_TYPE_P (type) |
| && integer_onep (TREE_OPERAND (arg0, 1)) |
| && integer_onep (arg1)) |
| return fold_build2_loc (loc, EQ_EXPR, type, arg0, |
| build_zero_cst (TREE_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: |
| /* Fold (X ^ 1) & 1 as (X & 1) == 0. */ |
| if (TREE_CODE (arg0) == BIT_XOR_EXPR |
| && INTEGRAL_TYPE_P (type) |
| && integer_onep (TREE_OPERAND (arg0, 1)) |
| && integer_onep (arg1)) |
| { |
| tree tem2; |
| tem = TREE_OPERAND (arg0, 0); |
| tem2 = fold_convert_loc (loc, TREE_TYPE (tem), arg1); |
| tem2 = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (tem), |
| tem, tem2); |
| return fold_build2_loc (loc, EQ_EXPR, type, tem2, |
| build_zero_cst (TREE_TYPE (tem))); |
| } |
| /* Fold ~X & 1 as (X & 1) == 0. */ |
| if (TREE_CODE (arg0) == BIT_NOT_EXPR |
| && INTEGRAL_TYPE_P (type) |
| && integer_onep (arg1)) |
| { |
| tree tem2; |
| tem = TREE_OPERAND (arg0, 0); |
| tem2 = fold_convert_loc (loc, TREE_TYPE (tem), arg1); |
| tem2 = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (tem), |
| tem, tem2); |
| return fold_build2_loc (loc, EQ_EXPR, type, tem2, |
| build_zero_cst (TREE_TYPE (tem))); |
| } |
| /* Fold !X & 1 as X == 0. */ |
| if (TREE_CODE (arg0) == TRUTH_NOT_EXPR |
| && integer_onep (arg1)) |
| { |
| tem = TREE_OPERAND (arg0, 0); |
| return fold_build2_loc (loc, EQ_EXPR, type, tem, |
| build_zero_cst (TREE_TYPE (tem))); |
| } |
| |
| /* Fold (X * Y) & -(1 << CST) to X * Y if Y is a constant |
| multiple of 1 << CST. */ |
| if (TREE_CODE (arg1) == INTEGER_CST) |
| { |
| wi::tree_to_wide_ref cst1 = wi::to_wide (arg1); |
| wide_int ncst1 = -cst1; |
| if ((cst1 & ncst1) == ncst1 |
| && multiple_of_p (type, arg0, |
| wide_int_to_tree (TREE_TYPE (arg1), ncst1))) |
| return fold_convert_loc (loc, type, arg0); |
| } |
| |
| /* Fold (X * CST1) & CST2 to zero if we can, or drop known zero |
| bits from CST2. */ |
| if (TREE_CODE (arg1) == INTEGER_CST |
| && TREE_CODE (arg0) == MULT_EXPR |
| && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) |
| { |
| wi::tree_to_wide_ref warg1 = wi::to_wide (arg1); |
| wide_int masked |
| = mask_with_tz (type, warg1, wi::to_wide (TREE_OPERAND (arg0, 1))); |
| |
| if (masked == 0) |
| return omit_two_operands_loc (loc, type, build_zero_cst (type), |
| arg0, arg1); |
| else if (masked != warg1) |
| { |
| /* Avoid the transform if arg1 is a mask of some |
| mode which allows further optimizations. */ |
| int pop = wi::popcount (warg1); |
| if (!(pop >= BITS_PER_UNIT |
| && pow2p_hwi (pop) |
| && wi::mask (pop, false, warg1.get_precision ()) == warg1)) |
| return fold_build2_loc (loc, code, type, op0, |
| wide_int_to_tree (type, masked)); |
| } |
| } |
| |
| /* 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)))) |
| { |
| prec = element_precision (TREE_TYPE (TREE_OPERAND (arg0, 0))); |
| |
| wide_int mask = wide_int::from (wi::to_wide (arg1), prec, UNSIGNED); |
| if (mask == -1) |
| return |
| fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); |
| } |
| |
| goto associate; |
| |
| case RDIV_EXPR: |
| /* Don't touch a floating-point divide by zero unless the mode |
| of the constant can represent infinity. */ |
| if (TREE_CODE (arg1) == REAL_CST |
| && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1))) |
| && real_zerop (arg1)) |
| return NULL_TREE; |
| |
| /* (-A) / (-B) -> A / B */ |
| if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1)) |
| return fold_build2_loc (loc, RDIV_EXPR, type, |
| TREE_OPERAND (arg0, 0), |
| negate_expr (arg1)); |
| if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0)) |
| return fold_build2_loc (loc, RDIV_EXPR, type, |
| negate_expr (arg0), |
| TREE_OPERAND (arg1, 0)); |
| return NULL_TREE; |
| |
| case TRUNC_DIV_EXPR: |
| /* Fall through */ |
| |
| case FLOOR_DIV_EXPR: |
| /* Simplify A / (B << N) where A and B are positive and B is |
| a power of 2, to A >> (N + log2(B)). */ |
| strict_overflow_p = false; |
| if (TREE_CODE (arg1) == LSHIFT_EXPR |
| && (TYPE_UNSIGNED (type) |
| || tree_expr_nonnegative_warnv_p (op0, &strict_overflow_p))) |
| { |
| tree sval = TREE_OPERAND (arg1, 0); |
| if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0) |
| { |
| tree sh_cnt = TREE_OPERAND (arg1, 1); |
| tree pow2 = build_int_cst (TREE_TYPE (sh_cnt), |
| wi::exact_log2 (wi::to_wide (sval))); |
| |
| if (strict_overflow_p) |
| fold_overflow_warning (("assuming signed overflow does not " |
| "occur when simplifying A / (B << N)"), |
| WARN_STRICT_OVERFLOW_MISC); |
| |
| sh_cnt = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (sh_cnt), |
| sh_cnt, pow2); |
| return fold_build2_loc (loc, RSHIFT_EXPR, type, |
| fold_convert_loc (loc, type, arg0), sh_cnt); |
| } |
| } |
| |
| /* Fall through */ |
| |
| case ROUND_DIV_EXPR: |
| case CEIL_DIV_EXPR: |
| case EXACT_DIV_EXPR: |
| if (integer_zerop (arg1)) |
| return NULL_TREE; |
| |
| /* Convert -A / -B to A / B when the type is signed and overflow is |
| undefined. */ |
| if ((!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) |
| && TREE_CODE (op0) == NEGATE_EXPR |
| && negate_expr_p (op1)) |
| { |
| if (ANY_INTEGRAL_TYPE_P (type)) |
| fold_overflow_warning (("assuming signed overflow does not occur " |
| "when distributing negation across " |
| "division"), |
| WARN_STRICT_OVERFLOW_MISC); |
| return fold_build2_loc (loc, code, type, |
| fold_convert_loc (loc, type, |
| TREE_OPERAND (arg0, 0)), |
| negate_expr (op1)); |
| } |
| if ((!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) |
| && TREE_CODE (arg1) == NEGATE_EXPR |
| && negate_expr_p (op0)) |
| { |
| if (ANY_INTEGRAL_TYPE_P (type)) |
| fold_overflow_warning (("assuming signed overflow does not occur " |
| "when distributing negation across " |
| "division"), |
| WARN_STRICT_OVERFLOW_MISC); |
| return fold_build2_loc (loc, code, type, |
| negate_expr (op0), |
| fold_convert_loc (loc, type, |
| TREE_OPERAND (arg1, 0))); |
| } |
| |
| /* If arg0 is a multiple of arg1, then rewrite to the fastest div |
| operation, EXACT_DIV_EXPR. |
| |
| Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now. |
| At one time others generated faster code, it's not clear if they do |
| 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, |
| fold_convert (type, arg0), |
| fold_convert (type, arg1)); |
| |
| strict_overflow_p = false; |
| if (TREE_CODE (arg1) == INTEGER_CST |
| && (tem = extract_muldiv (op0, arg1, code, NULL_TREE, |
| &strict_overflow_p)) != 0) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (("assuming signed overflow does not occur " |
| "when simplifying division"), |
| WARN_STRICT_OVERFLOW_MISC); |
| return fold_convert_loc (loc, type, tem); |
| } |
| |
| return NULL_TREE; |
| |
| case CEIL_MOD_EXPR: |
| case FLOOR_MOD_EXPR: |
| case ROUND_MOD_EXPR: |
| case TRUNC_MOD_EXPR: |
| strict_overflow_p = false; |
| if (TREE_CODE (arg1) == INTEGER_CST |
| && (tem = extract_muldiv (op0, arg1, code, NULL_TREE, |
| &strict_overflow_p)) != 0) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (("assuming signed overflow does not occur " |
| "when simplifying modulus"), |
| WARN_STRICT_OVERFLOW_MISC); |
| return fold_convert_loc (loc, type, tem); |
| } |
| |
| return NULL_TREE; |
| |
| case LROTATE_EXPR: |
| case RROTATE_EXPR: |
| case RSHIFT_EXPR: |
| case LSHIFT_EXPR: |
| /* Since negative shift count is not well-defined, |
| don't try to compute it in the compiler. */ |
| if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0) |
| return NULL_TREE; |
| |
| prec = element_precision (type); |
| |
| /* 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. */ |
| if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST |
| && (TREE_CODE (arg0) == BIT_AND_EXPR |
| || TREE_CODE (arg0) == BIT_IOR_EXPR |
| || TREE_CODE (arg0) == BIT_XOR_EXPR) |
| && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) |
| { |
| tree arg00 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); |
| tree arg01 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1)); |
| return fold_build2_loc (loc, TREE_CODE (arg0), type, |
| fold_build2_loc (loc, code, type, |
| arg00, arg1), |
| fold_build2_loc (loc, code, type, |
| arg01, arg1)); |
| } |
| |
| /* Two consecutive rotates adding up to the some integer |
| multiple of the precision of the type can be ignored. */ |
| if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST |
| && TREE_CODE (arg0) == RROTATE_EXPR |
| && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST |
| && wi::umod_trunc (wi::to_wide (arg1) |
| + wi::to_wide (TREE_OPERAND (arg0, 1)), |
| prec) == 0) |
| return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); |
| |
| return NULL_TREE; |
| |
| case MIN_EXPR: |
| case MAX_EXPR: |
| goto associate; |
| |
| case TRUTH_ANDIF_EXPR: |
| /* Note that the operands of this must be ints |
| and their values must be 0 or 1. |
| ("true" is a fixed value perhaps depending on the language.) */ |
| /* If first arg is constant zero, return it. */ |
| if (integer_zerop (arg0)) |
| return fold_convert_loc (loc, type, arg0); |
| /* FALLTHRU */ |
| case TRUTH_AND_EXPR: |
| /* If either arg is constant true, drop it. */ |
| if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) |
| return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1)); |
| if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1) |
| /* Preserve sequence points. */ |
| && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0))) |
| return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); |
| /* If second arg is constant zero, result is zero, but first arg |
| must be evaluated. */ |
| if (integer_zerop (arg1)) |
| return omit_one_operand_loc (loc, type, arg1, arg0); |
| /* Likewise for first arg, but note that only the TRUTH_AND_EXPR |
| case will be handled here. */ |
| if (integer_zerop (arg0)) |
| return omit_one_operand_loc (loc, type, arg0, arg1); |
| |
| /* !X && X is always false. */ |
| if (TREE_CODE (arg0) == TRUTH_NOT_EXPR |
| && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) |
| return omit_one_operand_loc (loc, type, integer_zero_node, arg1); |
| /* X && !X is always false. */ |
| if (TREE_CODE (arg1) == TRUTH_NOT_EXPR |
| && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) |
| return omit_one_operand_loc (loc, type, integer_zero_node, arg0); |
| |
| /* A < X && A + 1 > Y ==> A < X && A >= Y. Normally A + 1 > Y |
| means A >= Y && A != MAX, but in this case we know that |
| A < X <= MAX. */ |
| |
| if (!TREE_SIDE_EFFECTS (arg0) |
| && !TREE_SIDE_EFFECTS (arg1)) |
| { |
| tem = fold_to_nonsharp_ineq_using_bound (loc, arg0, arg1); |
| if (tem && !operand_equal_p (tem, arg0, 0)) |
| return fold_build2_loc (loc, code, type, tem, arg1); |
| |
| tem = fold_to_nonsharp_ineq_using_bound (loc, arg1, arg0); |
| if (tem && !operand_equal_p (tem, arg1, 0)) |
| return fold_build2_loc (loc, code, type, arg0, tem); |
| } |
| |
| if ((tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1)) |
| != NULL_TREE) |
| return tem; |
| |
| return NULL_TREE; |
| |
| case TRUTH_ORIF_EXPR: |
| /* Note that the operands of this must be ints |
| and their values must be 0 or true. |
| ("true" is a fixed value perhaps depending on the language.) */ |
| /* If first arg is constant true, return it. */ |
| if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) |
| return fold_convert_loc (loc, type, arg0); |
| /* FALLTHRU */ |
| case TRUTH_OR_EXPR: |
| /* If either arg is constant zero, drop it. */ |
| if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0)) |
| return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1)); |
| if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1) |
| /* Preserve sequence points. */ |
| && (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0))) |
| return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); |
| /* If second arg is constant true, result is true, but we must |
| evaluate first arg. */ |
| if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)) |
| return omit_one_operand_loc (loc, type, arg1, arg0); |
| /* Likewise for first arg, but note this only occurs here for |
| TRUTH_OR_EXPR. */ |
| if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) |
| return omit_one_operand_loc (loc, type, arg0, arg1); |
| |
| /* !X || X is always true. */ |
| if (TREE_CODE (arg0) == TRUTH_NOT_EXPR |
| && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) |
| return omit_one_operand_loc (loc, type, integer_one_node, arg1); |
| /* X || !X is always true. */ |
| if (TREE_CODE (arg1) == TRUTH_NOT_EXPR |
| && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) |
| return omit_one_operand_loc (loc, type, integer_one_node, arg0); |
| |
| /* (X && !Y) || (!X && Y) is X ^ Y */ |
| if (TREE_CODE (arg0) == TRUTH_AND_EXPR |
| && TREE_CODE (arg1) == TRUTH_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, TRUTH_NOT_EXPR, type, l0); |
| n1 = fold_build1_loc (loc, TRUTH_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, TRUTH_XOR_EXPR, type, l0, n1); |
| } |
| |
| if ((tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1)) |
| != NULL_TREE) |
| return tem; |
| |
| return NULL_TREE; |
| |
| case TRUTH_XOR_EXPR: |
| /* If the second arg is constant zero, drop it. */ |
| if (integer_zerop (arg1)) |
| return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); |
| /* If the second arg is constant true, this is a logical inversion. */ |
| if (integer_onep (arg1)) |
| { |
| tem = invert_truthvalue_loc (loc, arg0); |
| return non_lvalue_loc (loc, fold_convert_loc (loc, type, tem)); |
| } |
| /* Identical arguments cancel to zero. */ |
| if (operand_equal_p (arg0, arg1, 0)) |
| return omit_one_operand_loc (loc, type, integer_zero_node, arg0); |
| |
| /* !X ^ X is always true. */ |
| if (TREE_CODE (arg0) == TRUTH_NOT_EXPR |
| && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) |
| return omit_one_operand_loc (loc, type, integer_one_node, arg1); |
| |
| /* X ^ !X is always true. */ |
| if (TREE_CODE (arg1) == TRUTH_NOT_EXPR |
| && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) |
| return omit_one_operand_loc (loc, type, integer_one_node, arg0); |
| |
| return NULL_TREE; |
| |
| case EQ_EXPR: |
| case NE_EXPR: |
| STRIP_NOPS (arg0); |
| STRIP_NOPS (arg1); |
| |
| tem = fold_comparison (loc, code, type, op0, op1); |
| if (tem != NULL_TREE) |
| return tem; |
| |
| /* bool_var != 1 becomes !bool_var. */ |
| if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1) |
| && code == NE_EXPR) |
| return fold_convert_loc (loc, type, |
| fold_build1_loc (loc, TRUTH_NOT_EXPR, |
| TREE_TYPE (arg0), arg0)); |
| |
| /* bool_var == 0 becomes !bool_var. */ |
| if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1) |
| && code == EQ_EXPR) |
| return fold_convert_loc (loc, type, |
| fold_build1_loc (loc, TRUTH_NOT_EXPR, |
| TREE_TYPE (arg0), arg0)); |
| |
| /* !exp != 0 becomes !exp */ |
| if (TREE_CODE (arg0) == TRUTH_NOT_EXPR && integer_zerop (arg1) |
| && code == NE_EXPR) |
| return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0)); |
| |
| /* 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 |
| on machines that have only two-operand insns or on which a |
| constant cannot be the first operand. */ |
| if (TREE_CODE (arg0) == BIT_AND_EXPR |
| && integer_zerop (arg1)) |
| { |
| tree arg00 = TREE_OPERAND (arg0, 0); |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| if (TREE_CODE (arg00) == LSHIFT_EXPR |
| && integer_onep (TREE_OPERAND (arg00, 0))) |
| { |
| tree tem = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (arg00), |
| arg01, TREE_OPERAND (arg00, 1)); |
| tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0), tem, |
| build_one_cst (TREE_TYPE (arg0))); |
| return fold_build2_loc (loc, code, type, |
| fold_convert_loc (loc, TREE_TYPE (arg1), |
| tem), arg1); |
| } |
| else if (TREE_CODE (arg01) == LSHIFT_EXPR |
| && integer_onep (TREE_OPERAND (arg01, 0))) |
| { |
| tree tem = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (arg01), |
| arg00, TREE_OPERAND (arg01, 1)); |
| tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0), tem, |
| build_one_cst (TREE_TYPE (arg0))); |
| return fold_build2_loc (loc, code, type, |
| fold_convert_loc (loc, TREE_TYPE (arg1), |
| tem), arg1); |
| } |
| } |
| |
| /* Fold ((X >> C1) & C2) == 0 and ((X >> C1) & C2) != 0 where |
| C1 is a valid shift constant, and C2 is a power of two, i.e. |
| a single bit. */ |
| if (TREE_CODE (arg0) == BIT_AND_EXPR |
| && integer_pow2p (TREE_OPERAND (arg0, 1)) |
| && integer_zerop (arg1)) |
| { |
| tree arg00 = TREE_OPERAND (arg0, 0); |
| STRIP_NOPS (arg00); |
| if (TREE_CODE (arg00) == RSHIFT_EXPR |
| && TREE_CODE (TREE_OPERAND (arg00, 1)) == INTEGER_CST) |
| { |
| tree itype = TREE_TYPE (arg00); |
| tree arg001 = TREE_OPERAND (arg00, 1); |
| prec = TYPE_PRECISION (itype); |
| |
| /* Check for a valid shift count. */ |
| if (wi::ltu_p (wi::to_wide (arg001), prec)) |
| { |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| tree arg000 = TREE_OPERAND (arg00, 0); |
| unsigned HOST_WIDE_INT log2 = tree_log2 (arg01); |
| /* If (C2 << C1) doesn't overflow, then |
| ((X >> C1) & C2) != 0 can be rewritten as |
| (X & (C2 << C1)) != 0. */ |
| if ((log2 + TREE_INT_CST_LOW (arg001)) < prec) |
| { |
| tem = fold_build2_loc (loc, LSHIFT_EXPR, itype, |
| arg01, arg001); |
| tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, |
| arg000, tem); |
| return fold_build2_loc (loc, code, type, tem, |
| fold_convert_loc (loc, itype, arg1)); |
| } |
| /* Otherwise, for signed (arithmetic) shifts, |
| ((X >> C1) & C2) != 0 is rewritten as X < 0, and |
| ((X >> C1) & C2) == 0 is rewritten as X >= 0. */ |
| else if (!TYPE_UNSIGNED (itype)) |
| return fold_build2_loc (loc, code == EQ_EXPR ? GE_EXPR |
| : LT_EXPR, |
| type, arg000, |
| build_int_cst (itype, 0)); |
| /* Otherwise, of unsigned (logical) shifts, |
| ((X >> C1) & C2) != 0 is rewritten as (X,false), and |
| ((X >> C1) & C2) == 0 is rewritten as (X,true). */ |
| else |
| return omit_one_operand_loc (loc, type, |
| code == EQ_EXPR ? integer_one_node |
| : integer_zero_node, |
| arg000); |
| } |
| } |
| } |
| |
| /* 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) |
| /* Handle the constant case even without -O |
| to make sure the warnings are given. */ |
| && (optimize || TREE_CODE (arg1) == INTEGER_CST)) |
| { |
| t1 = optimize_bit_field_compare (loc, code, type, arg0, arg1); |
| if (t1) |
| return t1; |
| } |
| |
| /* Optimize comparisons of strlen vs zero to a compare of the |
| first character of the string vs zero. To wit, |
| strlen(ptr) == 0 => *ptr == 0 |
| strlen(ptr) != 0 => *ptr != 0 |
| Other cases should reduce to one of these two (or a constant) |
| due to the return value of strlen being unsigned. */ |
| if (TREE_CODE (arg0) == CALL_EXPR && integer_zerop (arg1)) |
| { |
| tree fndecl = get_callee_fndecl (arg0); |
| |
| if (fndecl |
| && fndecl_built_in_p (fndecl, BUILT_IN_STRLEN) |
| && call_expr_nargs (arg0) == 1 |
| && (TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (arg0, 0))) |
| == POINTER_TYPE)) |
| { |
| tree ptrtype |
| = build_pointer_type (build_qualified_type (char_type_node, |
| TYPE_QUAL_CONST)); |
| tree ptr = fold_convert_loc (loc, ptrtype, |
| CALL_EXPR_ARG (arg0, 0)); |
| tree iref = build_fold_indirect_ref_loc (loc, ptr); |
| return fold_build2_loc (loc, code, type, iref, |
| build_int_cst (TREE_TYPE (iref), 0)); |
| } |
| } |
| |
| /* Fold (X >> C) != 0 into X < 0 if C is one less than the width |
| of X. Similarly fold (X >> C) == 0 into X >= 0. */ |
| if (TREE_CODE (arg0) == RSHIFT_EXPR |
| && integer_zerop (arg1) |
| && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) |
| { |
| tree arg00 = TREE_OPERAND (arg0, 0); |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| tree itype = TREE_TYPE (arg00); |
| if (wi::to_wide (arg01) == element_precision (itype) - 1) |
| { |
| if (TYPE_UNSIGNED (itype)) |
| { |
| itype = signed_type_for (itype); |
| arg00 = fold_convert_loc (loc, itype, arg00); |
| } |
| return fold_build2_loc (loc, code == EQ_EXPR ? GE_EXPR : LT_EXPR, |
| type, arg00, build_zero_cst (itype)); |
| } |
| } |
| |
| /* 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 |
| && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_NOT_EXPR |
| && integer_zerop (arg1) |
| && integer_pow2p (TREE_OPERAND (arg0, 1))) |
| { |
| tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0), |
| TREE_OPERAND (TREE_OPERAND (arg0, 0), 0), |
| TREE_OPERAND (arg0, 1)); |
| return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, |
| type, tem, |
| fold_convert_loc (loc, TREE_TYPE (arg0), |
| arg1)); |
| } |
| |
| /* Fold ((X & C) ^ C) eq/ne 0 into (X & C) ne/eq 0, when the |
| constant C is a power of two, i.e. a single bit. */ |
| if (TREE_CODE (arg0) == BIT_XOR_EXPR |
| && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR |
| && integer_zerop (arg1) |
| && integer_pow2p (TREE_OPERAND (arg0, 1)) |
| && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), |
| TREE_OPERAND (arg0, 1), OEP_ONLY_CONST)) |
| { |
| tree arg00 = TREE_OPERAND (arg0, 0); |
| return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, |
| arg00, build_int_cst (TREE_TYPE (arg00), 0)); |
| } |
| |
| /* Likewise, fold ((X ^ C) & C) eq/ne 0 into (X & C) ne/eq 0, |
| when is C is a power of two, i.e. a single bit. */ |
| if (TREE_CODE (arg0) == BIT_AND_EXPR |
| && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_XOR_EXPR |
| && integer_zerop (arg1) |
| && integer_pow2p (TREE_OPERAND (arg0, 1)) |
| && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), |
| TREE_OPERAND (arg0, 1), OEP_ONLY_CONST)) |
| { |
| tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); |
| tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg000), |
| arg000, TREE_OPERAND (arg0, 1)); |
| return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, |
| tem, build_int_cst (TREE_TYPE (tem), 0)); |
| } |
| |
| if (integer_zerop (arg1) |
| && tree_expr_nonzero_p (arg0)) |
| { |
| tree res = constant_boolean_node (code==NE_EXPR, type); |
| return omit_one_operand_loc (loc, type, res, arg0); |
| } |
| |
| if (TREE_CODE (arg0) == BIT_XOR_EXPR |
| && TREE_CODE (arg1) == BIT_XOR_EXPR) |
| { |
| tree arg00 = TREE_OPERAND (arg0, 0); |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| tree arg10 = TREE_OPERAND (arg1, 0); |
| tree arg11 = TREE_OPERAND (arg1, 1); |
| tree itype = TREE_TYPE (arg0); |
| |
| /* Optimize (X ^ Z) op (Y ^ Z) as X op Y, and symmetries. |
| operand_equal_p guarantees no side-effects so we don't need |
| to use omit_one_operand on Z. */ |
| if (operand_equal_p (arg01, arg11, 0)) |
| return fold_build2_loc (loc, code, type, arg00, |
| fold_convert_loc (loc, TREE_TYPE (arg00), |
| arg10)); |
| if (operand_equal_p (arg01, arg10, 0)) |
| return fold_build2_loc (loc, code, type, arg00, |
| fold_convert_loc (loc, TREE_TYPE (arg00), |
| arg11)); |
| if (operand_equal_p (arg00, arg11, 0)) |
| return fold_build2_loc (loc, code, type, arg01, |
| fold_convert_loc (loc, TREE_TYPE (arg01), |
| arg10)); |
| if (operand_equal_p (arg00, arg10, 0)) |
| return fold_build2_loc (loc, code, type, arg01, |
| fold_convert_loc (loc, TREE_TYPE (arg01), |
| arg11)); |
| |
| /* Optimize (X ^ C1) op (Y ^ C2) as (X ^ (C1 ^ C2)) op Y. */ |
| if (TREE_CODE (arg01) == INTEGER_CST |
| && TREE_CODE (arg11) == INTEGER_CST) |
| { |
| tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg01, |
| fold_convert_loc (loc, itype, arg11)); |
| tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00, tem); |
| return fold_build2_loc (loc, code, type, tem, |
| fold_convert_loc (loc, itype, arg10)); |
| } |
| } |
| |
| /* Attempt to simplify equality/inequality comparisons of complex |
| values. Only lower the comparison if the result is known or |
| can be simplified to a single scalar comparison. */ |
| if ((TREE_CODE (arg0) == COMPLEX_EXPR |
| || TREE_CODE (arg0) == COMPLEX_CST) |
| && (TREE_CODE (arg1) == COMPLEX_EXPR |
| || TREE_CODE (arg1) == COMPLEX_CST)) |
| { |
| tree real0, imag0, real1, imag1; |
| tree rcond, icond; |
| |
| if (TREE_CODE (arg0) == COMPLEX_EXPR) |
| { |
| real0 = TREE_OPERAND (arg0, 0); |
| imag0 = TREE_OPERAND (arg0, 1); |
| } |
| else |
| { |
| real0 = TREE_REALPART (arg0); |
| imag0 = TREE_IMAGPART (arg0); |
| } |
| |
| if (TREE_CODE (arg1) == COMPLEX_EXPR) |
| { |
| real1 = TREE_OPERAND (arg1, 0); |
| imag1 = TREE_OPERAND (arg1, 1); |
| } |
| else |
| { |
| real1 = TREE_REALPART (arg1); |
| imag1 = TREE_IMAGPART (arg1); |
| } |
| |
| rcond = fold_binary_loc (loc, code, type, real0, real1); |
| if (rcond && TREE_CODE (rcond) == INTEGER_CST) |
| { |
| if (integer_zerop (rcond)) |
| { |
| if (code == EQ_EXPR) |
| return omit_two_operands_loc (loc, type, boolean_false_node, |
| imag0, imag1); |
| return fold_build2_loc (loc, NE_EXPR, type, imag0, imag1); |
| } |
| else |
| { |
| if (code == NE_EXPR) |
| return omit_two_operands_loc (loc, type, boolean_true_node, |
| imag0, imag1); |
| return fold_build2_loc (loc, EQ_EXPR, type, imag0, imag1); |
| } |
| } |
| |
| icond = fold_binary_loc (loc, code, type, imag0, imag1); |
| if (icond && TREE_CODE (icond) == INTEGER_CST) |
| { |
| if (integer_zerop (icond)) |
| { |
| if (code == EQ_EXPR) |
| return omit_two_operands_loc (loc, type, boolean_false_node, |
| real0, real1); |
| return fold_build2_loc (loc, NE_EXPR, type, real0, real1); |
| } |
| else |
| { |
| if (code == NE_EXPR) |
| return omit_two_operands_loc (loc, type, boolean_true_node, |
| real0, real1); |
| return fold_build2_loc (loc, EQ_EXPR, type, real0, real1); |
| } |
| } |
| } |
| |
| return NULL_TREE; |
| |
| case LT_EXPR: |
| case GT_EXPR: |
| case LE_EXPR: |
| case GE_EXPR: |
| tem = fold_comparison (loc, code, type, op0, op1); |
| if (tem != NULL_TREE) |
| return tem; |
| |
| /* Transform comparisons of the form X +- C CMP X. */ |
| 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 (arg0)) |
| { |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| enum tree_code code0 = TREE_CODE (arg0); |
| int is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1; |
| |
| /* (X - c) > X becomes false. */ |
| if (code == GT_EXPR |
| && ((code0 == MINUS_EXPR && is_positive >= 0) |
| || (code0 == PLUS_EXPR && is_positive <= 0))) |
| return constant_boolean_node (0, type); |
| |
| /* Likewise (X + c) < X becomes false. */ |
| if (code == LT_EXPR |
| && ((code0 == PLUS_EXPR && is_positive >= 0) |
| || (code0 == MINUS_EXPR && is_positive <= 0))) |
| return constant_boolean_node (0, type); |
| |
| /* Convert (X - c) <= X to true. */ |
| if (!HONOR_NANS (arg1) |
| && code == LE_EXPR |
| && ((code0 == MINUS_EXPR && is_positive >= 0) |
| || (code0 == PLUS_EXPR && is_positive <= 0))) |
| return constant_boolean_node (1, type); |
| |
| /* Convert (X + c) >= X to true. */ |
| if (!HONOR_NANS (arg1) |
| && code == GE_EXPR |
| && ((code0 == PLUS_EXPR && is_positive >= 0) |
| || (code0 == MINUS_EXPR && is_positive <= 0))) |
| return constant_boolean_node (1, type); |
| } |
| |
| /* If we are comparing an ABS_EXPR with a constant, we can |
| convert all the cases into explicit comparisons, but they may |
| well not be faster than doing the ABS and one comparison. |
| But ABS (X) <= C is a range comparison, which becomes a subtraction |
| and a comparison, and is probably faster. */ |
| if (code == LE_EXPR |
| && TREE_CODE (arg1) == INTEGER_CST |
| && TREE_CODE (arg0) == ABS_EXPR |
| && ! TREE_SIDE_EFFECTS (arg0) |
| && (tem = negate_expr (arg1)) != 0 |
| && TREE_CODE (tem) == INTEGER_CST |
| && !TREE_OVERFLOW (tem)) |
| return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type, |
| build2 (GE_EXPR, type, |
| TREE_OPERAND (arg0, 0), tem), |
| build2 (LE_EXPR, type, |
| TREE_OPERAND (arg0, 0), arg1)); |
| |
| /* Convert ABS_EXPR<x> >= 0 to true. */ |
| strict_overflow_p = false; |
| if (code == GE_EXPR |
| && (integer_zerop (arg1) |
| || (! HONOR_NANS (arg0) |
| && real_zerop (arg1))) |
| && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (("assuming signed overflow does not occur " |
| "when simplifying comparison of " |
| "absolute value and zero"), |
| WARN_STRICT_OVERFLOW_CONDITIONAL); |
| return omit_one_operand_loc (loc, type, |
| constant_boolean_node (true, type), |
| arg0); |
| } |
| |
| /* Convert ABS_EXPR<x> < 0 to false. */ |
| strict_overflow_p = false; |
| if (code == LT_EXPR |
| && (integer_zerop (arg1) || real_zerop (arg1)) |
| && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) |
| { |
| if (strict_overflow_p) |
| fold_overflow_warning (("assuming signed overflow does not occur " |
| "when simplifying comparison of " |
| "absolute value and zero"), |
| WARN_STRICT_OVERFLOW_CONDITIONAL); |
| return omit_one_operand_loc (loc, type, |
| constant_boolean_node (false, type), |
| arg0); |
| } |
| |
| /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0 |
| and similarly for >= into !=. */ |
| if ((code == LT_EXPR || code == GE_EXPR) |
| && TYPE_UNSIGNED (TREE_TYPE (arg0)) |
| && TREE_CODE (arg1) == LSHIFT_EXPR |
| && integer_onep (TREE_OPERAND (arg1, 0))) |
| return build2_loc (loc, code == LT_EXPR ? EQ_EXPR : NE_EXPR, type, |
| build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, |
| TREE_OPERAND (arg1, 1)), |
| build_zero_cst (TREE_TYPE (arg0))); |
| |
| /* Similarly for X < (cast) (1 << Y). But cast can't be narrowing, |
| otherwise Y might be >= # of bits in X's type and thus e.g. |
| (unsigned char) (1 << Y) for Y 15 might be 0. |
| If the cast is widening, then 1 << Y should have unsigned type, |
| otherwise if Y is number of bits in the signed shift type minus 1, |
| we can't optimize this. E.g. (unsigned long long) (1 << Y) for Y |
| 31 might be 0xffffffff80000000. */ |
| if ((code == LT_EXPR || code == GE_EXPR) |
| && (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) |
| || VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg0))) |
| && TYPE_UNSIGNED (TREE_TYPE (arg0)) |
| && CONVERT_EXPR_P (arg1) |
| && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR |
| && (element_precision (TREE_TYPE (arg1)) |
| >= element_precision (TREE_TYPE (TREE_OPERAND (arg1, 0)))) |
| && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0))) |
| || (element_precision (TREE_TYPE (arg1)) |
| == element_precision (TREE_TYPE (TREE_OPERAND (arg1, 0))))) |
| && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0))) |
| { |
| tem = build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, |
| TREE_OPERAND (TREE_OPERAND (arg1, 0), 1)); |
| return build2_loc (loc, code == LT_EXPR ? EQ_EXPR : NE_EXPR, type, |
| fold_convert_loc (loc, TREE_TYPE (arg0), tem), |
| build_zero_cst (TREE_TYPE (arg0))); |
| } |
| |
| return NULL_TREE; |
| |
| case UNORDERED_EXPR: |
| case ORDERED_EXPR: |
| case UNLT_EXPR: |
| case UNLE_EXPR: |
| case UNGT_EXPR: |
| case UNGE_EXPR: |
| case UNEQ_EXPR: |
| case LTGT_EXPR: |
| /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */ |
| { |
| 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); |
| |
| 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)); |
| } |
| |
| return NULL_TREE; |
| |
| case COMPOUND_EXPR: |
| /* When pedantic, a compound expression can be neither an lvalue |
| nor an integer constant expression. */ |
| if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1)) |
| return NULL_TREE; |
| /* Don't let (0, 0) be null pointer constant. */ |
| tem = integer_zerop (arg1) ? build1_loc (loc, NOP_EXPR, type, arg1) |
| : fold_convert_loc (loc, type, arg1); |
| return tem; |
| |
| case ASSERT_EXPR: |
| /* An ASSERT_EXPR should never be passed to fold_binary. */ |
| gcc_unreachable (); |
| |
| default: |
| return NULL_TREE; |
| } /* switch (code) */ |
| } |
| |
| /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M, |
| ((A & N) + B) & M -> (A + B) & M |
| Similarly if (N & M) == 0, |
| ((A | N) + B) & M -> (A + B) & M |
| and for - instead of + (or unary - instead of +) |
| and/or ^ instead of |. |
| If B is constant and (B & M) == 0, fold into A & M. |
| |
| This function is a helper for match.pd patterns. Return non-NULL |
| type in which the simplified operation should be performed only |
| if any optimization is possible. |
| |
| ARG1 is M above, ARG00 is left operand of +/-, if CODE00 is BIT_*_EXPR, |
| then ARG00{0,1} are operands of that bitop, otherwise CODE00 is ERROR_MARK. |
| Similarly for ARG01, CODE01 and ARG01{0,1}, just for the right operand of |
| +/-. */ |
| tree |
| fold_bit_and_mask (tree type, tree arg1, enum tree_code code, |
| tree arg00, enum tree_code code00, tree arg000, tree arg001, |
| tree arg01, enum tree_code code01, tree arg010, tree arg011, |
| tree *pmop) |
| { |
| gcc_assert (TREE_CODE (arg1) == INTEGER_CST); |
| gcc_assert (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR); |
| wi::tree_to_wide_ref cst1 = wi::to_wide (arg1); |
| if (~cst1 == 0 |
| || (cst1 & (cst1 + 1)) != 0 |
| || !INTEGRAL_TYPE_P (type) |
| || (!TYPE_OVERFLOW_WRAPS (type) |
| && TREE_CODE (type) != INTEGER_TYPE) |
| || (wi::max_value (type) & cst1) != cst1) |
| return NULL_TREE; |
| |
| enum tree_code codes[2] = { code00, code01 }; |
| tree arg0xx[4] = { arg000, arg001, arg010, arg011 }; |
| int which = 0; |
| wide_int cst0; |
| |
| /* Now we know that arg0 is (C + D) or (C - D) or -C and |
| arg1 (M) is == (1LL << cst) - 1. |
| Store C into PMOP[0] and D into PMOP[1]. */ |
| pmop[0] = arg00; |
| pmop[1] = arg01; |
| which = code != NEGATE_EXPR; |
| |
| for (; which >= 0; which--) |
| switch (codes[which]) |
| { |
| case BIT_AND_EXPR: |
| case BIT_IOR_EXPR: |
| case BIT_XOR_EXPR: |
| gcc_assert (TREE_CODE (arg0xx[2 * which + 1]) == INTEGER_CST); |
| cst0 = wi::to_wide (arg0xx[2 * which + 1]) & cst1; |
| if (codes[which] == BIT_AND_EXPR) |
| { |
| if (cst0 != cst1) |
| break; |
| } |
| else if (cst0 != 0) |
| break; |
| /* If C or D is of the form (A & N) where |
| (N & M) == M, or of the form (A | N) or |
| (A ^ N) where (N & M) == 0, replace it with A. */ |
| pmop[which] = arg0xx[2 * which]; |
| break; |
| case ERROR_MARK: |
| if (TREE_CODE (pmop[which]) != INTEGER_CST) |
| break; |
| /* If C or D is a N where (N & M) == 0, it can be |
| omitted (replaced with 0). */ |
| if ((code == PLUS_EXPR |
| || (code == MINUS_EXPR && which == 0)) |
| && (cst1 & wi::to_wide (pmop[which])) == 0) |
| pmop[which] = build_int_cst (type, 0); |
| /* Similarly, with C - N where (-N & M) == 0. */ |
| if (code == MINUS_EXPR |
| && which == 1 |
| && (cst1 & -wi::to_wide (pmop[which])) == 0) |
| pmop[which] = build_int_cst (type, 0); |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* Only build anything new if we optimized one or both arguments above. */ |
| if (pmop[0] == arg00 && pmop[1] == arg01) |
| return NULL_TREE; |
| |
| if (TYPE_OVERFLOW_WRAPS (type)) |
| return type; |
| else |
| return unsigned_type_for (type); |
| } |
| |
| /* Used by contains_label_[p1]. */ |
| |
| struct contains_label_data |
| { |
| hash_set<tree> *pset; |
| bool inside_switch_p; |
| }; |
| |
| /* Callback for walk_tree, looking for LABEL_EXPR. Return *TP if it is |
| a LABEL_EXPR or CASE_LABEL_EXPR not inside of another SWITCH_EXPR; otherwise |
| return NULL_TREE. Do not check the subtrees of GOTO_EXPR. */ |
| |
| static tree |
| contains_label_1 (tree *tp, int *walk_subtrees, void *data) |
| { |
| contains_label_data *d = (contains_label_data *) data; |
| switch (TREE_CODE (*tp)) |
| { |
| case LABEL_EXPR: |
| return *tp; |
| |
| case CASE_LABEL_EXPR: |
| if (!d->inside_switch_p) |
| return *tp; |
| return NULL_TREE; |
| |
| case SWITCH_EXPR: |
| if (!d->inside_switch_p) |
| { |
| if (walk_tree (&SWITCH_COND (*tp), contains_label_1, data, d->pset)) |
| return *tp; |
| d->inside_switch_p = true; |
| if (walk_tree (&SWITCH_BODY (*tp), contains_label_1, data, d->pset)) |
| return *tp; |
| d->inside_switch_p = false; |
| *walk_subtrees = 0; |
| } |
| return NULL_TREE; |
| |
| case GOTO_EXPR: |
| *walk_subtrees = 0; |
| return NULL_TREE; |
| |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| /* Return whether the sub-tree ST contains a label which is accessible from |
| outside the sub-tree. */ |
| |
| static bool |
| contains_label_p (tree st) |
| { |
| hash_set<tree> pset; |
| contains_label_data data = { &pset, false }; |
| return walk_tree (&st, contains_label_1, &data, &pset) != NULL_TREE; |
| } |
| |
| /* Fold a ternary expression of code CODE and type TYPE with operands |
| OP0, OP1, and OP2. Return the folded expression if folding is |
| successful. Otherwise, return NULL_TREE. */ |
| |
| tree |
| fold_ternary_loc (location_t loc, enum tree_code code, tree type, |
| tree op0, tree op1, tree op2) |
| { |
| tree tem; |
| tree arg0 = NULL_TREE, arg1 = NULL_TREE, arg2 = NULL_TREE; |
| enum tree_code_class kind = TREE_CODE_CLASS (code); |
| |
| gcc_assert (IS_EXPR_CODE_CLASS (kind) |
| && TREE_CODE_LENGTH (code) == 3); |
| |
| /* If this is a commutative operation, and OP0 is a constant, move it |
| to OP1 to reduce the number of tests below. */ |
| if (commutative_ternary_tree_code (code) |
| && tree_swap_operands_p (op0, op1)) |
| return fold_build3_loc (loc, code, type, op1, op0, op2); |
| |
| tem = generic_simplify (loc, code, type, op0, op1, op2); |
| if (tem) |
| return tem; |
| |
| /* Strip any conversions that don't change the mode. This is safe |
| for every expression, except for a comparison expression because |
| its signedness is derived from its operands. So, in the latter |
| case, only strip conversions that don't change the signedness. |
| |
| Note that this is done as an internal manipulation within the |
| constant folder, in order to find the simplest representation of |
| the arguments so that their form can be studied. In any cases, |
| the appropriate type conversions should be put back in the tree |
| that will get out of the constant folder. */ |
| if (op0) |
| { |
| arg0 = op0; |
| STRIP_NOPS (arg0); |
| } |
| |
| if (op1) |
| { |
| arg1 = op1; |
| STRIP_NOPS (arg1); |
| } |
| |
| if (op2) |
| { |
| arg2 = op2; |
| STRIP_NOPS (arg2); |
| } |
| |
| switch (code) |
| { |
| case COMPONENT_REF: |
| if (TREE_CODE (arg0) == CONSTRUCTOR |
| && ! type_contains_placeholder_p (TREE_TYPE (arg0))) |
| { |
| unsigned HOST_WIDE_INT idx; |
| tree field, value; |
| FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, field, value) |
| if (field == arg1) |
| return value; |
| } |
| return NULL_TREE; |
| |
| case COND_EXPR: |
| case VEC_COND_EXPR: |
| /* Pedantic ANSI C says that a conditional expression is never an lvalue, |
| so all simple results must be passed through pedantic_non_lvalue. */ |
| if (TREE_CODE (arg0) == INTEGER_CST) |
| { |
| tree unused_op = integer_zerop (arg0) ? op1 : op2; |
| tem = integer_zerop (arg0) ? op2 : op1; |
| /* Only optimize constant conditions when the selected branch |
| has the same type as the COND_EXPR. This avoids optimizing |
| away "c ? x : throw", where the throw has a void type. |
| Avoid throwing away that operand which contains label. */ |
| if ((!TREE_SIDE_EFFECTS (unused_op) |
| || !contains_label_p (unused_op)) |
| && (! VOID_TYPE_P (TREE_TYPE (tem)) |
| || VOID_TYPE_P (type))) |
| return protected_set_expr_location_unshare (tem, loc); |
| return NULL_TREE; |
| } |
| else if (TREE_CODE (arg0) == VECTOR_CST) |
| { |
| unsigned HOST_WIDE_INT nelts; |
| if ((TREE_CODE (arg1) == VECTOR_CST |
| || TREE_CODE (arg1) == CONSTRUCTOR) |
| && (TREE_CODE (arg2) == VECTOR_CST |
| || TREE_CODE (arg2) == CONSTRUCTOR) |
| && TYPE_VECTOR_SUBPARTS (type).is_constant (&nelts)) |
| { |
| vec_perm_builder sel (nelts, nelts, 1); |
| for (unsigned int i = 0; i < nelts; i++) |
| { |
| tree val = VECTOR_CST_ELT (arg0, i); |
| if (integer_all_onesp (val)) |
| sel.quick_push (i); |
| else if (integer_zerop (val)) |
| sel.quick_push (nelts + i); |
| else /* Currently unreachable. */ |
| return NULL_TREE; |
| } |
| vec_perm_indices indices (sel, 2, nelts); |
| tree t = fold_vec_perm (type, arg1, arg2, indices); |
| if (t != NULL_TREE) |
| return t; |
| } |
| } |
| |
| /* If we have A op B ? A : C, we may be able to convert this to a |
| simpler expression, depending on the operation and the values |
| of B and C. Signed zeros prevent all of these transformations, |
| for reasons given above each one. |
| |
| Also try swapping the arguments and inverting the conditional. */ |
| if (COMPARISON_CLASS_P (arg0) |
| && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), op1) |
| && !HONOR_SIGNED_ZEROS (op1)) |
| { |
| tem = fold_cond_expr_with_comparison (loc, type, TREE_CODE (arg0), |
| TREE_OPERAND (arg0, 0), |
| TREE_OPERAND (arg0, 1), |
| op1, op2); |
| if (tem) |
| return tem; |
| } |
| |
| if (COMPARISON_CLASS_P (arg0) |
| && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), op2) |
| && !HONOR_SIGNED_ZEROS (op2)) |
| { |
| enum tree_code comp_code = TREE_CODE (arg0); |
| tree arg00 = TREE_OPERAND (arg0, 0); |
| tree arg01 = TREE_OPERAND (arg0, 1); |
| comp_code = invert_tree_comparison (comp_code, HONOR_NANS (arg00)); |
| if (comp_code != ERROR_MARK) |
| tem = fold_cond_expr_with_comparison (loc, type, comp_code, |
| arg00, |
| arg01, |
| op2, op1); |
| if (tem) |
| return tem; |
| } |
| |
| /* If the second operand is simpler than the third, swap them |
| since that produces better jump optimization results. */ |
| if (truth_value_p (TREE_CODE (arg0)) |
| && tree_swap_operands_p (op1, op2)) |
| { |
| location_t loc0 = expr_location_or (arg0, loc); |
| /* See if this can be inverted. If it can't, possibly because |
| it was a floating-point inequality comparison, don't do |
| anything. */ |
| tem = fold_invert_truthvalue (loc0, arg0); |
| if (tem) |
| return fold_build3_loc (loc, code, type, tem, op2, op1); |
| } |
| |
| /* Convert A ? 1 : 0 to simply A. */ |
| if ((code == VEC_COND_EXPR ? integer_all_onesp (op1) |
| : (integer_onep (op1) |
| && !VECTOR_TYPE_P (type))) |
| && integer_zerop (op2) |
| /* If we try to convert OP0 to our type, the |
| call to fold will try to move the conversion inside |
| a COND, which will recurse. In that case, the COND_EXPR |
| is probably the best choice, so leave it alone. */ |
| && type == TREE_TYPE (arg0)) |
| return protected_set_expr_location_unshare (arg0, loc); |
| |
| /* Convert A ? 0 : 1 to !A. This prefers the use of NOT_EXPR |
| over COND_EXPR in cases such as floating point comparisons. */ |
| if (integer_zerop (op1) |
| && code == COND_EXPR |
| && integer_onep (op2) |
| && !VECTOR_TYPE_P (type) |
| && truth_value_p (TREE_CODE (arg0))) |
| return fold_convert_loc (loc, type, |
| invert_truthvalue_loc (loc, arg0)); |
| |
| /* A < 0 ? <sign bit of A> : 0 is simply (A & <sign bit of A>). */ |
| if (TREE_CODE (arg0) == LT_EXPR |
| && integer_zerop (TREE_OPERAND (arg0, 1)) |
| && integer_zerop (op2) |
| && (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1))) |
| { |
| /* sign_bit_p looks through both zero and sign extensions, |
| but for this optimization only sign extensions are |
| usable. */ |
| tree tem2 = TREE_OPERAND (arg0, 0); |
| while (tem != tem2) |
| { |
| if (TREE_CODE (tem2) != NOP_EXPR |
| || TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (tem2, 0)))) |
| { |
| tem = NULL_TREE; |
| break; |
| } |
| tem2 = TREE_OPERAND (tem2, 0); |
| } |
| /* sign_bit_p only checks ARG1 bits within A's precision. |
| If <sign bit of A> has wider type than A, bits outside |
| of A's precision in <sign bit of A> need to be checked. |
| If they are all 0, this optimization needs to be done |
| in unsigned A's type, if they are all 1 in signed A's type, |
| otherwise this can't be done. */ |
| if (tem |
| && TYPE_PRECISION (TREE_TYPE (tem)) |
| < TYPE_PRECISION (TREE_TYPE (arg1)) |
| && TYPE_PRECISION (TREE_TYPE (tem)) |
| < TYPE_PRECISION (type)) |
| { |
| int inner_width, outer_width; |
| tree tem_type; |
| |
| inner_width = TYPE_PRECISION (TREE_TYPE (tem)); |
| outer_width = TYPE_PRECISION (TREE_TYPE (arg1)); |
| if (outer_width > TYPE_PRECISION (type)) |
| outer_width = TYPE_PRECISION (type); |
| |
| wide_int mask = wi::shifted_mask |
| (inner_width, outer_width - inner_width, false, |
| TYPE_PRECISION (TREE_TYPE (arg1))); |
| |
| wide_int common = mask & wi::to_wide (arg1); |
| if (common == mask) |
| { |
| tem_type = signed_type_for (TREE_TYPE (tem)); |
| tem = fold_convert_loc (loc, tem_type, tem); |
| } |
| else if (common == 0) |
| { |
| tem_type = unsigned_type_for (TREE_TYPE (tem)); |
| tem = fold_convert_loc (loc, tem_type, tem); |
| } |
| else |
| tem = NULL; |
| } |
| |
| if (tem) |
| return |
| fold_convert_loc (loc, type, |
| fold_build2_loc (loc, BIT_AND_EXPR, |
| TREE_TYPE (tem), tem, |
| fold_convert_loc (loc, |
| TREE_TYPE (tem), |
| arg1))); |
| } |
| |
| /* (A >> N) & 1 ? (1 << N) : 0 is simply A & (1 << N). A & 1 was |
| already handled above. */ |
| if (TREE_CODE (arg0) == BIT_AND_EXPR |
| && integer_onep (TREE_OPERAND (arg0, 1)) |
| && integer_zerop (op2) |
| && integer_pow2p (arg1)) |
| { |
| tree tem = TREE_OPERAND (arg0, 0); |
| STRIP_NOPS (tem); |
| if (TREE_CODE (tem) == RSHIFT_EXPR |
| && tree_fits_uhwi_p (TREE_OPERAND (tem, 1)) |
| && (unsigned HOST_WIDE_INT) tree_log2 (arg1) |
| == tree_to_uhwi (TREE_OPERAND (tem, 1))) |
| return fold_build2_loc (loc, BIT_AND_EXPR, type, |
| fold_convert_loc (loc, type, |
| TREE_OPERAND (tem, 0)), |
| op1); |
| } |
| |
| /* A & N ? N : 0 is simply A & N if N is a power of two. This |
| is probably obsolete because the first operand should be a |
| truth value (that's why we have the two cases above), but let's |
| leave it in until we can confirm this for all front-ends. */ |
| if (integer_zerop (op2) |
| && TREE_CODE (arg0) == NE_EXPR |
| && integer_zerop (TREE_OPERAND (arg0, 1)) |
| && integer_pow2p (arg1) |
| && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR |
| && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), |
| arg1, OEP_ONLY_CONST) |
| /* operand_equal_p compares just value, not precision, so e.g. |
| arg1 could be 8-bit -128 and be power of two, but BIT_AND_EXPR |
| second operand 32-bit -128, which is not a power of two (or vice |
| versa. */ |
| && integer_pow2p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1))) |
| return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); |
| |
| /* Disable the transformations below for vectors, since |
| fold_binary_op_with_conditional_arg may undo them immediately, |
| yielding an infinite loop. */ |
| if (code == VEC_COND_EXPR) |
| return NULL_TREE; |
| |
| /* Convert A ? B : 0 into A && B if A and B are truth values. */ |
| if (integer_zerop (op2) |
| && truth_value_p (TREE_CODE (arg0)) |
| && truth_value_p (TREE_CODE (arg1)) |
| && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) |
| return fold_build2_loc (loc, code == VEC_COND_EXPR ? BIT_AND_EXPR |
| : TRUTH_ANDIF_EXPR, |
| type, fold_convert_loc (loc, type, arg0), op1); |
| |
| /* Convert A ? B : 1 into !A || B if A and B are truth values. */ |
| if (code == VEC_COND_EXPR ? integer_all_onesp (op2) : integer_onep (op2) |
| && truth_value_p (TREE_CODE (arg0)) |
| && truth_value_p (TREE_CODE (arg1)) |
| && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) |
| { |
| location_t loc0 = expr_location_or (arg0, loc); |
| /* Only perform transformation if ARG0 is easily inverted. */ |
| tem = fold_invert_truthvalue (loc0, arg0); |
| if (tem) |
| return fold_build2_loc (loc, code == VEC_COND_EXPR |
| ? BIT_IOR_EXPR |
| : TRUTH_ORIF_EXPR, |
| type, fold_convert_loc (loc, type, tem), |
| op1); |
| } |
| |
| /* Convert A ? 0 : B into !A && B if A and B are truth values. */ |
| if (integer_zerop (arg1) |
| && truth_value_p (TREE_CODE (arg0)) |
| && truth_value_p (TREE_CODE (op2)) |
| && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) |
| { |
| location_t loc0 = expr_location_or (arg0, loc); |
| /* Only perform transformation if ARG0 is easily inverted. */ |
| tem = fold_invert_truthvalue (loc0, arg0); |
| if (tem) |
| return fold_build2_loc (loc, code == VEC_COND_EXPR |
| ? BIT_AND_EXPR : TRUTH_ANDIF_EXPR, |
| type, fold_convert_loc (loc, type, tem), |
| op2); |
| } |
| |
| /* Convert A ? 1 : B into A || B if A and B are truth values. */ |
| if (code == VEC_COND_EXPR ? integer_all_onesp (arg1) : integer_onep (arg1) |
| && truth_value_p (TREE_CODE (arg0)) |
| && truth_value_p (TREE_CODE (op2)) |
| && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) |
| return fold_build2_loc (loc, code == VEC_COND_EXPR |
| ? BIT_IOR_EXPR : TRUTH_ORIF_EXPR, |
| type, fold_convert_loc (loc, type, arg0), op2); |
| |
| return NULL_TREE; |
| |
| case CALL_EXPR: |
| /* CALL_EXPRs used to be ternary exprs. Catch any mistaken uses |
| of fold_ternary on them. */ |
| gcc_unreachable (); |
| |
| case BIT_FIELD_REF: |
| if (TREE_CODE (arg0) == VECTOR_CST |
| && (type == TREE_TYPE (TREE_TYPE (arg0)) |
| || (VECTOR_TYPE_P (type) |
| && TREE_TYPE (type) == TREE_TYPE (TREE_TYPE (arg0)))) |
| && tree_fits_uhwi_p (op1) |
| && tree_fits_uhwi_p (op2)) |
| { |
| tree eltype = TREE_TYPE (TREE_TYPE (arg0)); |
| unsigned HOST_WIDE_INT width |
| = (TREE_CODE (eltype) == BOOLEAN_TYPE |
| ? TYPE_PRECISION (eltype) : tree_to_uhwi (TYPE_SIZE (eltype))); |
| unsigned HOST_WIDE_INT n = tree_to_uhwi (arg1); |
| unsigned HOST_WIDE_INT idx = tree_to_uhwi (op2); |
| |
| if (n != 0 |
| && (idx % width) == 0 |
| && (n % width) == 0 |
| && known_le ((idx + n) / width, |
| TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))) |
| { |
| idx = idx / width; |
| n = n / width; |
| |
| if (TREE_CODE (arg0) == VECTOR_CST) |
| { |
| if (n == 1) |
| { |
| tem = VECTOR_CST_ELT (arg0, idx); |
| if (VECTOR_TYPE_P (type)) |
| tem = fold_build1 (VIEW_CONVERT_EXPR, type, tem); |
| return tem; |
| } |
| |
| tree_vector_builder vals (type, n, 1); |
| for (unsigned i = 0; i < n; ++i) |
| vals.quick_push (VECTOR_CST_ELT (arg0, idx + i)); |
| return vals.build (); |
| } |
| } |
| } |
| |
| /* On constants we can use native encode/interpret to constant |
| fold (nearly) all BIT_FIELD_REFs. */ |
| if (CONSTANT_CLASS_P (arg0) |
| && can_native_interpret_type_p (type) |
| && BITS_PER_UNIT == 8 |
| && tree_fits_uhwi_p (op1) |
| && tree_fits_uhwi_p (op2)) |
| { |
| unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); |
| unsigned HOST_WIDE_INT bitsize = tree_to_uhwi (op1); |
| /* Limit us to a reasonable amount of work. To relax the |
| other limitations we need bit-shifting of the buffer |
| and rounding up the size. */ |
| if (bitpos % BITS_PER_UNIT == 0 |
| && bitsize % BITS_PER_UNIT == 0 |
| && bitsize <= MAX_BITSIZE_MODE_ANY_MODE) |
| { |
| unsigned char b[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT]; |
| unsigned HOST_WIDE_INT len |
| = native_encode_expr (arg0, b, bitsize / BITS_PER_UNIT, |
| bitpos / BITS_PER_UNIT); |
| if (len > 0 |
| && len * BITS_PER_UNIT >= bitsize) |
| { |
| tree v = native_interpret_expr (type, b, |
| bitsize / BITS_PER_UNIT); |
| if (v) |
| return v; |
| } |
| } |
| } |
| |
| return NULL_TREE; |
| |
| case VEC_PERM_EXPR: |
| /* Perform constant folding of BIT_INSERT_EXPR. */ |
| if (TREE_CODE (arg2) == VECTOR_CST |
| && TREE_CODE (op0) == VECTOR_CST |
| && TREE_CODE (op1) == VECTOR_CST) |
| { |
| /* Build a vector of integers from the tree mask. */ |
| vec_perm_builder builder; |
| if (!tree_to_vec_perm_builder (&builder, arg2)) |
| return NULL_TREE; |
| |
| /* Create a vec_perm_indices for the integer vector. */ |
| poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (type); |
| bool single_arg = (op0 == op1); |
| vec_perm_indices sel (builder, single_arg ? 1 : 2, nelts); |
| return fold_vec_perm (type, op0, op1, sel); |
| } |
| return NULL_TREE; |
| |
| case BIT_INSERT_EXPR: |
| /* Perform (partial) constant folding of BIT_INSERT_EXPR. */ |
| if (TREE_CODE (arg0) == INTEGER_CST |
| && TREE_CODE (arg1) == INTEGER_CST) |
| { |
| unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); |
| unsigned bitsize = TYPE_PRECISION (TREE_TYPE (arg1)); |
| wide_int tem = (wi::to_wide (arg0) |
| & wi::shifted_mask (bitpos, bitsize, true, |
| TYPE_PRECISION (type))); |
| wide_int tem2 |
| = wi::lshift (wi::zext (wi::to_wide (arg1, TYPE_PRECISION (type)), |
| bitsize), bitpos); |
| return wide_int_to_tree (type, wi::bit_or (tem, tem2)); |
| } |
| else if (TREE_CODE (arg0) == VECTOR_CST |
| && CONSTANT_CLASS_P (arg1) |
| && types_compatible_p (TREE_TYPE (TREE_TYPE (arg0)), |
| TREE_TYPE (arg1))) |
| { |
| unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2); |
| unsigned HOST_WIDE_INT elsize |
| = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg1))); |
| if (bitpos % elsize == 0) |
| { |
| unsigned k = bitpos / elsize; |
| unsigned HOST_WIDE_INT nelts; |
| if (operand_equal_p (VECTOR_CST_ELT (arg0, k), arg1, 0)) |
| return arg0; |
| else if (VECTOR_CST_NELTS (arg0).is_constant (&nelts)) |
| { |
| tree_vector_builder elts (type, nelts, 1); |
| elts.quick_grow (nelts); |
| for (unsigned HOST_WIDE_INT i = 0; i < nelts; ++i) |
| elts[i] = (i == k ? arg1 : VECTOR_CST_ELT (arg0, i)); |
| return elts.build (); |
| } |
| } |
| } |
| return NULL_TREE; |
| |
| default: |
| return NULL_TREE; |
| } /* switch (code) */ |
| } |
| |
| /* Gets the element ACCESS_INDEX from CTOR, which must be a CONSTRUCTOR |
| of an array (or vector). *CTOR_IDX if non-NULL is updated with the |
| constructor element index of the value returned. If the element is |
| not found NULL_TREE is returned and *CTOR_IDX is updated to |
| the index of the element after the ACCESS_INDEX position (which |
| may be outside of the CTOR array). */ |
| |
| tree |
| get_array_ctor_element_at_index (tree ctor, offset_int access_index, |
| unsigned *ctor_idx) |
| { |
| tree index_type = NULL_TREE; |
| signop index_sgn = UNSIGNED; |
| offset_int low_bound = 0; |
| |
| if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE) |
| { |
| tree domain_type = TYPE_DOMAIN (TREE_TYPE (ctor)); |
| if (domain_type && TYPE_MIN_VALUE (domain_type)) |
| { |
| /* Static constructors for variably sized objects makes no sense. */ |
| gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST); |
| index_type = TREE_TYPE (TYPE_MIN_VALUE (domain_type)); |
| /* ??? When it is obvious that the range is signed, treat it so. */ |
| if (TYPE_UNSIGNED (index_type) |
| && TYPE_MAX_VALUE (domain_type) |
| && tree_int_cst_lt (TYPE_MAX_VALUE (domain_type), |
| TYPE_MIN_VALUE (domain_type))) |
| { |
| index_sgn = SIGNED; |
| low_bound |
| = offset_int::from (wi::to_wide (TYPE_MIN_VALUE (domain_type)), |
| SIGNED); |
| } |
| else |
| { |
| index_sgn = TYPE_SIGN (index_type); |
| low_bound = wi::to_offset (TYPE_MIN_VALUE (domain_type)); |
| } |
| } |
| } |
| |
| if (index_type) |
| access_index = wi::ext (access_index, TYPE_PRECISION (index_type), |
| index_sgn); |
| |
| offset_int index = low_bound; |
| if (index_type) |
| index = wi::ext (index, TYPE_PRECISION (index_type), index_sgn); |
| |
| offset_int max_index = index; |
| unsigned cnt; |
| tree cfield, cval; |
| bool first_p = true; |
| |
| FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) |
| { |
| /* Array constructor might explicitly set index, or specify a range, |
| or leave index NULL meaning that it is next index after previous |
| one. */ |
| if (cfield) |
| { |
| if (TREE_CODE (cfield) == INTEGER_CST) |
| max_index = index |
| = offset_int::from (wi::to_wide (cfield), index_sgn); |
| else |
| { |
| gcc_assert (TREE_CODE (cfield) == RANGE_EXPR); |
| index = offset_int::from (wi::to_wide (TREE_OPERAND (cfield, 0)), |
| index_sgn); |
| max_index |
| = offset_int::from (wi::to_wide (TREE_OPERAND (cfield, 1)), |
| index_sgn); |
| gcc_checking_assert (wi::le_p (index, max_index, index_sgn)); |
| } |
| } |
| else if (!first_p) |
| { |
| index = max_index + 1; |
| if (index_type) |
| index = wi::ext (index, TYPE_PRECISION (index_type), index_sgn); |
| gcc_checking_assert (wi::gt_p (index, max_index, index_sgn)); |
| max_index = index; |
| } |
| else |
| first_p = false; |
| |
| /* Do we have match? */ |
| if (wi::cmp (access_index, index, index_sgn) >= 0) |
| { |
| if (wi::cmp (access_index, max_index, index_sgn) <= 0) |
| { |
| if (ctor_idx) |
| *ctor_idx = cnt; |
| return cval; |
| } |
| } |
| else if (in_gimple_form) |
| /* We're past the element we search for. Note during parsing |
| the elements might not be sorted. |
| ??? We should use a binary search and a flag on the |
| CONSTRUCTOR as to whether elements are sorted in declaration |
| order. */ |
| break; |
| } |
| if (ctor_idx) |
| *ctor_idx = cnt; |
| return NULL_TREE; |
| } |
| |
| /* Perform constant folding and related simplification of EXPR. |
| The related simplifications include x*1 => x, x*0 => 0, etc., |
| and application of the associative law. |
| NOP_EXPR conversions may be removed freely (as long as we |
| are careful not to change the type of the overall expression). |
| We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR, |
| but we can constant-fold them if they have constant operands. */ |
| |
| #ifdef ENABLE_FOLD_CHECKING |
| # define fold(x) fold_1 (x) |
| static tree fold_1 (tree); |
| static |
| #endif |
| tree |
| fold (tree expr) |
| { |
| const tree t = expr; |
| enum tree_code code = TREE_CODE (t); |
| enum tree_code_class kind = TREE_CODE_CLASS (code); |
| tree tem; |
| location_t loc = EXPR_LOCATION (expr); |
| |
| /* Return right away if a constant. */ |
| if (kind == tcc_constant) |
| return t; |
| |
| /* CALL_EXPR-like objects with variable numbers of operands are |
| treated specially. */ |
| if (kind == tcc_vl_exp) |
| { |
| if (code == CALL_EXPR) |
| { |
| tem = fold_call_expr (loc, expr, false); |
| return tem ? tem : expr; |
| } |
| return expr; |
| } |
| |
| if (IS_EXPR_CODE_CLASS (kind)) |
| { |
| tree type = TREE_TYPE (t); |
| tree op0, op1, op2; |
| |
| switch (TREE_CODE_LENGTH (code)) |
| { |
| case 1: |
| op0 = TREE_OPERAND (t, 0); |
| tem = fold_unary_loc (loc, code, type, op0); |
| return tem ? tem : expr; |
| case 2: |
| op0 = TREE_OPERAND (t, 0); |
| op1 = TREE_OPERAND (t, 1); |
| tem = fold_binary_loc (loc, code, type, op0, op1); |
| return tem ? tem : expr; |
| case 3: |
| op0 = TREE_OPERAND (t, 0); |
| op1 = TREE_OPERAND (t, 1); |
| op2 = TREE_OPERAND (t, 2); |
| tem = fold_ternary_loc (loc, code, type, op0, op1, op2); |
| return tem ? tem : expr; |
| default: |
| break; |
| } |
| } |
| |
| switch (code) |
| { |
| case ARRAY_REF: |
| { |
| tree op0 = TREE_OPERAND (t, 0); |
| tree op1 = TREE_OPERAND (t, 1); |
| |
| if (TREE_CODE (op1) == INTEGER_CST |
| && TREE_CODE (op0) == CONSTRUCTOR |
| && ! type_contains_placeholder_p (TREE_TYPE (op0))) |
| { |
| tree val = get_array_ctor_element_at_index (op0, |
| wi::to_offset (op1)); |
| if (val) |
| return val; |
| } |
| |
| return t; |
| } |
| |
| /* Return a VECTOR_CST if possible. */ |
| case CONSTRUCTOR: |
| { |
| tree type = TREE_TYPE (t); |
| if (TREE_CODE (type) != VECTOR_TYPE) |
| return t; |
| |
| unsigned i; |
| tree val; |
| FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, val) |
| if (! CONSTANT_CLASS_P (val)) |
| return t; |
| |
| return build_vector_from_ctor (type, CONSTRUCTOR_ELTS (t)); |
| } |
| |
| case CONST_DECL: |
| return fold (DECL_INITIAL (t)); |
| |
| default: |
| return t; |
| } /* switch (code) */ |
| } |
| |
| #ifdef ENABLE_FOLD_CHECKING |
| #undef fold |
| |
| static void fold_checksum_tree (const_tree, struct md5_ctx *, |
| hash_table<nofree_ptr_hash<const tree_node> > *); |
| static void fold_check_failed (const_tree, const_tree); |
| void print_fold_checksum (const_tree); |
| |
| /* When --enable-checking=fold, compute a digest of expr before |
| and after actual fold call to see if fold did not accidentally |
| change original expr. */ |
| |
| tree |
| fold (tree expr) |
| { |
| tree ret; |
| struct md5_ctx ctx; |
| unsigned char checksum_before[16], checksum_after[16]; |
| hash_table<nofree_ptr_hash<const tree_node> > ht (32); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (expr, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before); |
| ht.empty (); |
| |
| ret = fold_1 (expr); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (expr, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after); |
| |
| if (memcmp (checksum_before, checksum_after, 16)) |
| fold_check_failed (expr, ret); |
| |
| return ret; |
| } |
| |
| void |
| print_fold_checksum (const_tree expr) |
| { |
| struct md5_ctx ctx; |
| unsigned char checksum[16], cnt; |
| hash_table<nofree_ptr_hash<const tree_node> > ht (32); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (expr, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum); |
| for (cnt = 0; cnt < 16; ++cnt) |
| fprintf (stderr, "%02x", checksum[cnt]); |
| putc ('\n', stderr); |
| } |
| |
| static void |
| fold_check_failed (const_tree expr ATTRIBUTE_UNUSED, const_tree ret ATTRIBUTE_UNUSED) |
| { |
| internal_error ("fold check: original tree changed by fold"); |
| } |
| |
| static void |
| fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, |
| hash_table<nofree_ptr_hash <const tree_node> > *ht) |
| { |
| const tree_node **slot; |
| enum tree_code code; |
| union tree_node *buf; |
| int i, len; |
| |
| recursive_label: |
| if (expr == NULL) |
| return; |
| slot = ht->find_slot (expr, INSERT); |
| if (*slot != NULL) |
| return; |
| *slot = expr; |
| code = TREE_CODE (expr); |
| if (TREE_CODE_CLASS (code) == tcc_declaration |
| && HAS_DECL_ASSEMBLER_NAME_P (expr)) |
| { |
| /* Allow DECL_ASSEMBLER_NAME and symtab_node to be modified. */ |
| size_t sz = tree_size (expr); |
| buf = XALLOCAVAR (union tree_node, sz); |
| memcpy ((char *) buf, expr, sz); |
| SET_DECL_ASSEMBLER_NAME ((tree) buf, NULL); |
| buf->decl_with_vis.symtab_node = NULL; |
| buf->base.nowarning_flag = 0; |
| expr = (tree) buf; |
| } |
| else if (TREE_CODE_CLASS (code) == tcc_type |
| && (TYPE_POINTER_TO (expr) |
| || TYPE_REFERENCE_TO (expr) |
| || TYPE_CACHED_VALUES_P (expr) |
| || TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) |
| || TYPE_NEXT_VARIANT (expr) |
| || TYPE_ALIAS_SET_KNOWN_P (expr))) |
| { |
| /* Allow these fields to be modified. */ |
| tree tmp; |
| size_t sz = tree_size (expr); |
| buf = XALLOCAVAR (union tree_node, sz); |
| memcpy ((char *) buf, expr, sz); |
| expr = tmp = (tree) buf; |
| TYPE_CONTAINS_PLACEHOLDER_INTERNAL (tmp) = 0; |
| TYPE_POINTER_TO (tmp) = NULL; |
| TYPE_REFERENCE_TO (tmp) = NULL; |
| TYPE_NEXT_VARIANT (tmp) = NULL; |
| TYPE_ALIAS_SET (tmp) = -1; |
| if (TYPE_CACHED_VALUES_P (tmp)) |
| { |
| TYPE_CACHED_VALUES_P (tmp) = 0; |
| TYPE_CACHED_VALUES (tmp) = NULL; |
| } |
| } |
| else if (warning_suppressed_p (expr) && (DECL_P (expr) || EXPR_P (expr))) |
| { |
| /* Allow the no-warning bit to be set. Perhaps we shouldn't allow |
| that and change builtins.c etc. instead - see PR89543. */ |
| size_t sz = tree_size (expr); |
| buf = XALLOCAVAR (union tree_node, sz); |
| memcpy ((char *) buf, expr, sz); |
| buf->base.nowarning_flag = 0; |
| expr = (tree) buf; |
| } |
| md5_process_bytes (expr, tree_size (expr), ctx); |
| if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) |
| fold_checksum_tree (TREE_TYPE (expr), ctx, ht); |
| if (TREE_CODE_CLASS (code) != tcc_type |
| && TREE_CODE_CLASS (code) != tcc_declaration |
| && code != TREE_LIST |
| && code != SSA_NAME |
| && CODE_CONTAINS_STRUCT (code, TS_COMMON)) |
| fold_checksum_tree (TREE_CHAIN (expr), ctx, ht); |
| switch (TREE_CODE_CLASS (code)) |
| { |
| case tcc_constant: |
| switch (code) |
| { |
| case STRING_CST: |
| md5_process_bytes (TREE_STRING_POINTER (expr), |
| TREE_STRING_LENGTH (expr), ctx); |
| break; |
| case COMPLEX_CST: |
| fold_checksum_tree (TREE_REALPART (expr), ctx, ht); |
| fold_checksum_tree (TREE_IMAGPART (expr), ctx, ht); |
| break; |
| case VECTOR_CST: |
| len = vector_cst_encoded_nelts (expr); |
| for (i = 0; i < len; ++i) |
| fold_checksum_tree (VECTOR_CST_ENCODED_ELT (expr, i), ctx, ht); |
| break; |
| default: |
| break; |
| } |
| break; |
| case tcc_exceptional: |
| switch (code) |
| { |
| case TREE_LIST: |
| fold_checksum_tree (TREE_PURPOSE (expr), ctx, ht); |
| fold_checksum_tree (TREE_VALUE (expr), ctx, ht); |
| expr = TREE_CHAIN (expr); |
| goto recursive_label; |
| break; |
| case TREE_VEC: |
| for (i = 0; i < TREE_VEC_LENGTH (expr); ++i) |
| fold_checksum_tree (TREE_VEC_ELT (expr, i), ctx, ht); |
| break; |
| default: |
| break; |
| } |
| break; |
| case tcc_expression: |
| case tcc_reference: |
| case tcc_comparison: |
| case tcc_unary: |
| case tcc_binary: |
| case tcc_statement: |
| case tcc_vl_exp: |
| len = TREE_OPERAND_LENGTH (expr); |
| for (i = 0; i < len; ++i) |
| fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht); |
| break; |
| case tcc_declaration: |
| fold_checksum_tree (DECL_NAME (expr), ctx, ht); |
| fold_checksum_tree (DECL_CONTEXT (expr), ctx, ht); |
| if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_COMMON)) |
| { |
| fold_checksum_tree (DECL_SIZE (expr), ctx, ht); |
| fold_checksum_tree (DECL_SIZE_UNIT (expr), ctx, ht); |
| fold_checksum_tree (DECL_INITIAL (expr), ctx, ht); |
| fold_checksum_tree (DECL_ABSTRACT_ORIGIN (expr), ctx, ht); |
| fold_checksum_tree (DECL_ATTRIBUTES (expr), ctx, ht); |
| } |
| |
| if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_NON_COMMON)) |
| { |
| if (TREE_CODE (expr) == FUNCTION_DECL) |
| { |
| fold_checksum_tree (DECL_VINDEX (expr), ctx, ht); |
| fold_checksum_tree (DECL_ARGUMENTS (expr), ctx, ht); |
| } |
| fold_checksum_tree (DECL_RESULT_FLD (expr), ctx, ht); |
| } |
| break; |
| case tcc_type: |
| if (TREE_CODE (expr) == ENUMERAL_TYPE) |
| fold_checksum_tree (TYPE_VALUES (expr), ctx, ht); |
| fold_checksum_tree (TYPE_SIZE (expr), ctx, ht); |
| fold_checksum_tree (TYPE_SIZE_UNIT (expr), ctx, ht); |
| fold_checksum_tree (TYPE_ATTRIBUTES (expr), ctx, ht); |
| fold_checksum_tree (TYPE_NAME (expr), ctx, ht); |
| if (INTEGRAL_TYPE_P (expr) |
| || SCALAR_FLOAT_TYPE_P (expr)) |
| { |
| fold_checksum_tree (TYPE_MIN_VALUE (expr), ctx, ht); |
| fold_checksum_tree (TYPE_MAX_VALUE (expr), ctx, ht); |
| } |
| fold_checksum_tree (TYPE_MAIN_VARIANT (expr), ctx, ht); |
| if (TREE_CODE (expr) == RECORD_TYPE |
| || TREE_CODE (expr) == UNION_TYPE |
| || TREE_CODE (expr) == QUAL_UNION_TYPE) |
| fold_checksum_tree (TYPE_BINFO (expr), ctx, ht); |
| fold_checksum_tree (TYPE_CONTEXT (expr), ctx, ht); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* Helper function for outputting the checksum of a tree T. When |
| debugging with gdb, you can "define mynext" to be "next" followed |
| by "call debug_fold_checksum (op0)", then just trace down till the |
| outputs differ. */ |
| |
| DEBUG_FUNCTION void |
| debug_fold_checksum (const_tree t) |
| { |
| int i; |
| unsigned char checksum[16]; |
| struct md5_ctx ctx; |
| hash_table<nofree_ptr_hash<const tree_node> > ht (32); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (t, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum); |
| ht.empty (); |
| |
| for (i = 0; i < 16; i++) |
| fprintf (stderr, "%d ", checksum[i]); |
| |
| fprintf (stderr, "\n"); |
| } |
| |
| #endif |
| |
| /* Fold a unary tree expression with code CODE of type TYPE with an |
| operand OP0. LOC is the location of the resulting expression. |
| Return a folded expression if successful. Otherwise, return a tree |
| expression with code CODE of type TYPE with an operand OP0. */ |
| |
| tree |
| fold_build1_loc (location_t loc, |
| enum tree_code code, tree type, tree op0 MEM_STAT_DECL) |
| { |
| tree tem; |
| #ifdef ENABLE_FOLD_CHECKING |
| unsigned char checksum_before[16], checksum_after[16]; |
| struct md5_ctx ctx; |
| hash_table<nofree_ptr_hash<const tree_node> > ht (32); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op0, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before); |
| ht.empty (); |
| #endif |
| |
| tem = fold_unary_loc (loc, code, type, op0); |
| if (!tem) |
| tem = build1_loc (loc, code, type, op0 PASS_MEM_STAT); |
| |
| #ifdef ENABLE_FOLD_CHECKING |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op0, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after); |
| |
| if (memcmp (checksum_before, checksum_after, 16)) |
| fold_check_failed (op0, tem); |
| #endif |
| return tem; |
| } |
| |
| /* Fold a binary tree expression with code CODE of type TYPE with |
| operands OP0 and OP1. LOC is the location of the resulting |
| expression. Return a folded expression if successful. Otherwise, |
| return a tree expression with code CODE of type TYPE with operands |
| OP0 and OP1. */ |
| |
| tree |
| fold_build2_loc (location_t loc, |
| enum tree_code code, tree type, tree op0, tree op1 |
| MEM_STAT_DECL) |
| { |
| tree tem; |
| #ifdef ENABLE_FOLD_CHECKING |
| unsigned char checksum_before_op0[16], |
| checksum_before_op1[16], |
| checksum_after_op0[16], |
| checksum_after_op1[16]; |
| struct md5_ctx ctx; |
| hash_table<nofree_ptr_hash<const tree_node> > ht (32); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op0, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before_op0); |
| ht.empty (); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op1, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before_op1); |
| ht.empty (); |
| #endif |
| |
| tem = fold_binary_loc (loc, code, type, op0, op1); |
| if (!tem) |
| tem = build2_loc (loc, code, type, op0, op1 PASS_MEM_STAT); |
| |
| #ifdef ENABLE_FOLD_CHECKING |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op0, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after_op0); |
| ht.empty (); |
| |
| if (memcmp (checksum_before_op0, checksum_after_op0, 16)) |
| fold_check_failed (op0, tem); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op1, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after_op1); |
| |
| if (memcmp (checksum_before_op1, checksum_after_op1, 16)) |
| fold_check_failed (op1, tem); |
| #endif |
| return tem; |
| } |
| |
| /* Fold a ternary tree expression with code CODE of type TYPE with |
| operands OP0, OP1, and OP2. Return a folded expression if |
| successful. Otherwise, return a tree expression with code CODE of |
| type TYPE with operands OP0, OP1, and OP2. */ |
| |
| tree |
| fold_build3_loc (location_t loc, enum tree_code code, tree type, |
| tree op0, tree op1, tree op2 MEM_STAT_DECL) |
| { |
| tree tem; |
| #ifdef ENABLE_FOLD_CHECKING |
| unsigned char checksum_before_op0[16], |
| checksum_before_op1[16], |
| checksum_before_op2[16], |
| checksum_after_op0[16], |
| checksum_after_op1[16], |
| checksum_after_op2[16]; |
| struct md5_ctx ctx; |
| hash_table<nofree_ptr_hash<const tree_node> > ht (32); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op0, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before_op0); |
| ht.empty (); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op1, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before_op1); |
| ht.empty (); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op2, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before_op2); |
| ht.empty (); |
| #endif |
| |
| gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); |
| tem = fold_ternary_loc (loc, code, type, op0, op1, op2); |
| if (!tem) |
| tem = build3_loc (loc, code, type, op0, op1, op2 PASS_MEM_STAT); |
| |
| #ifdef ENABLE_FOLD_CHECKING |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op0, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after_op0); |
| ht.empty (); |
| |
| if (memcmp (checksum_before_op0, checksum_after_op0, 16)) |
| fold_check_failed (op0, tem); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op1, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after_op1); |
| ht.empty (); |
| |
| if (memcmp (checksum_before_op1, checksum_after_op1, 16)) |
| fold_check_failed (op1, tem); |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (op2, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after_op2); |
| |
| if (memcmp (checksum_before_op2, checksum_after_op2, 16)) |
| fold_check_failed (op2, tem); |
| #endif |
| return tem; |
| } |
| |
| /* Fold a CALL_EXPR expression of type TYPE with operands FN and NARGS |
| arguments in ARGARRAY, and a null static chain. |
| Return a folded expression if successful. Otherwise, return a CALL_EXPR |
| of type TYPE from the given operands as constructed by build_call_array. */ |
| |
| tree |
| fold_build_call_array_loc (location_t loc, tree type, tree fn, |
| int nargs, tree *argarray) |
| { |
| tree tem; |
| #ifdef ENABLE_FOLD_CHECKING |
| unsigned char checksum_before_fn[16], |
| checksum_before_arglist[16], |
| checksum_after_fn[16], |
| checksum_after_arglist[16]; |
| struct md5_ctx ctx; |
| hash_table<nofree_ptr_hash<const tree_node> > ht (32); |
| int i; |
| |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (fn, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before_fn); |
| ht.empty (); |
| |
| md5_init_ctx (&ctx); |
| for (i = 0; i < nargs; i++) |
| fold_checksum_tree (argarray[i], &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_before_arglist); |
| ht.empty (); |
| #endif |
| |
| tem = fold_builtin_call_array (loc, type, fn, nargs, argarray); |
| if (!tem) |
| tem = build_call_array_loc (loc, type, fn, nargs, argarray); |
| |
| #ifdef ENABLE_FOLD_CHECKING |
| md5_init_ctx (&ctx); |
| fold_checksum_tree (fn, &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after_fn); |
| ht.empty (); |
| |
| if (memcmp (checksum_before_fn, checksum_after_fn, 16)) |
| fold_check_failed (fn, tem); |
| |
| md5_init_ctx (&ctx); |
| for (i = 0; i < nargs; i++) |
| fold_checksum_tree (argarray[i], &ctx, &ht); |
| md5_finish_ctx (&ctx, checksum_after_arglist); |
| |
| if (memcmp (checksum_before_arglist, checksum_after_arglist, 16)) |
| fold_check_failed (NULL_TREE, tem); |
| #endif |
| return tem; |
| } |
| |
| /* Perform constant folding and related simplification of initializer |
| expression EXPR. These behave identically to "fold_buildN" but ignore |
| potential run-time traps and exceptions that fold must preserve. */ |
| |
| #define START_FOLD_INIT \ |
| int saved_signaling_nans = flag_signaling_nans;\ |
| int saved_trapping_math = flag_trapping_math;\ |
| int saved_rounding_math = flag_rounding_math;\ |
| int saved_trapv = flag_trapv;\ |
| int saved_folding_initializer = folding_initializer;\ |
| flag_signaling_nans = 0;\ |
| flag_trapping_math = 0;\ |
| flag_rounding_math = 0;\ |
| flag_trapv = 0;\ |
| folding_initializer = 1; |
| |
| #define END_FOLD_INIT \ |
| flag_signaling_nans = saved_signaling_nans;\ |
| flag_trapping_math = saved_trapping_math;\ |
| flag_rounding_math = saved_rounding_math;\ |
| flag_trapv = saved_trapv;\ |
| folding_initializer = saved_folding_initializer; |
| |
| tree |
| fold_build1_initializer_loc (location_t loc, enum tree_code code, |
| tree type, tree op) |
| { |
| tree result; |
| START_FOLD_INIT; |
| |
| result = fold_build1_loc (loc, code, type, op); |
| |
| END_FOLD_INIT; |
| return result; |
| } |
| |
| tree |
| fold_build2_initializer_loc (location_t loc, enum tree_code code, |
| tree type, tree op0, tree op1) |
| { |
| tree result; |
| START_FOLD_INIT; |
| |
| result = fold_build2_loc (loc, code, type, op0, op1); |
| |
| END_FOLD_INIT; |
| return result; |
| } |
| |
| tree |
| fold_build_call_array_initializer_loc (location_t loc, tree type, tree fn, |
| int nargs, tree *argarray) |
| { |
| tree result; |
| START_FOLD_INIT; |
| |
| result = fold_build_call_array_loc (loc, type, fn, nargs, argarray); |
| |
| END_FOLD_INIT; |
| return result; |
| } |
| |
| #undef START_FOLD_INIT |
| #undef END_FOLD_INIT |
| |
| /* Determine if first argument is a multiple of second argument. Return 0 if |
| it is not, or we cannot easily determined it to be. |
| |
| An example of the sort of thing we care about (at this point; this routine |
| could surely be made more general, and expanded to do what the *_DIV_EXPR's |
| fold cases do now) is discovering that |
| |
| SAVE_EXPR (I) * SAVE_EXPR (J * 8) |
| |
| is a multiple of |
| |
| SAVE_EXPR (J * 8) |
| |
| when we know that the two SAVE_EXPR (J * 8) nodes are the same node. |
| |
| This code also handles discovering that |
| |
| SAVE_EXPR (I) * SAVE_EXPR (J * 8) |
| |
| is a multiple of 8 so we don't have to worry about dealing with a |
| possible remainder. |
| |
| Note that we *look* inside a SAVE_EXPR only to determine how it was |
| calculated; it is not safe for fold to do much of anything else with the |
| internals of a SAVE_EXPR, since it cannot know when it will be evaluated |
| at run time. For example, the latter example above *cannot* be implemented |
| as SAVE_EXPR (I) * J or any variant thereof, since the value of J at |
| evaluation time of the original SAVE_EXPR is not necessarily the same at |
| the time the new expression is evaluated. The only optimization of this |
| sort that would be valid is changing |
| |
| SAVE_EXPR (I) * SAVE_EXPR (SAVE_EXPR (J) * 8) |
| |
| divided by 8 to |
| |
| SAVE_EXPR (I) * SAVE_EXPR (J) |
| |
| (where the same SAVE_EXPR (J) is used in the original and the |
| transformed version). */ |
| |
| int |
| multiple_of_p (tree type, const_tree top, const_tree bottom) |
| { |
| gimple *stmt; |
| tree t1, op1, op2; |
| |
| if (operand_equal_p (top, bottom, 0)) |
| return 1; |
| |
| if (TREE_CODE (type) != INTEGER_TYPE) |
| return 0; |
| |
| switch (TREE_CODE (top)) |
| { |
| case BIT_AND_EXPR: |
| /* Bitwise and provides a power of two multiple. If the mask is |
| a multiple of BOTTOM then TOP is a multiple of BOTTOM. */ |
| if (!integer_pow2p (bottom)) |
| return 0; |
| return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) |
| || multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); |
| |
| case MULT_EXPR: |
| if (TREE_CODE (bottom) == INTEGER_CST) |
| { |
| op1 = TREE_OPERAND (top, 0); |
| op2 = TREE_OPERAND (top, 1); |
| if (TREE_CODE (op1) == INTEGER_CST) |
| std::swap (op1, op2); |
| if (TREE_CODE (op2) == INTEGER_CST) |
| { |
| if (multiple_of_p (type, op2, bottom)) |
| return 1; |
| /* Handle multiple_of_p ((x * 2 + 2) * 4, 8). */ |
| if (multiple_of_p (type, bottom, op2)) |
| { |
| widest_int w = wi::sdiv_trunc (wi::to_widest (bottom), |
| wi::to_widest (op2)); |
| if (wi::fits_to_tree_p (w, TREE_TYPE (bottom))) |
| { |
| op2 = wide_int_to_tree (TREE_TYPE (bottom), w); |
| return multiple_of_p (type, op1, op2); |
| } |
| } |
| return multiple_of_p (type, op1, bottom); |
| } |
| } |
| return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) |
| || multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); |
| |
| case MINUS_EXPR: |
| /* It is impossible to prove if op0 - op1 is multiple of bottom |
| precisely, so be conservative here checking if both op0 and op1 |
| are multiple of bottom. Note we check the second operand first |
| since it's usually simpler. */ |
| return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) |
| && multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); |
| |
| case PLUS_EXPR: |
| /* The same as MINUS_EXPR, but handle cases like op0 + 0xfffffffd |
| as op0 - 3 if the expression has unsigned type. For example, |
| (X / 3) + 0xfffffffd is multiple of 3, but 0xfffffffd is not. */ |
| op1 = TREE_OPERAND (top, 1); |
| if (TYPE_UNSIGNED (type) |
| && TREE_CODE (op1) == INTEGER_CST && tree_int_cst_sign_bit (op1)) |
| op1 = fold_build1 (NEGATE_EXPR, type, op1); |
| return (multiple_of_p (type, op1, bottom) |
| && multiple_of_p (type, TREE_OPERAND (top, 0), bottom)); |
| |
| case LSHIFT_EXPR: |
| if (TREE_CODE (TREE_OPERAND (top, 1)) == INTEGER_CST) |
| { |
| op1 = TREE_OPERAND (top, 1); |
| /* const_binop may not detect overflow correctly, |
| so check for it explicitly here. */ |
| if (wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)), |
| wi::to_wide (op1)) |
| && (t1 = fold_convert (type, |
| const_binop (LSHIFT_EXPR, size_one_node, |
| op1))) != 0 |
| && !TREE_OVERFLOW (t1)) |
| return multiple_of_p (type, t1, bottom); |
| } |
| return 0; |
| |
| case NOP_EXPR: |
| /* Can't handle conversions from non-integral or wider integral type. */ |
| if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE) |
| || (TYPE_PRECISION (type) |
| < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0))))) |
| return 0; |
| |
| /* fall through */ |
| |
| case SAVE_EXPR: |
| return multiple_of_p (type, TREE_OPERAND (top, 0), bottom); |
| |
| case COND_EXPR: |
| return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom) |
| && multiple_of_p (type, TREE_OPERAND (top, 2), bottom)); |
| |
| case INTEGER_CST: |
| if (TREE_CODE (bottom) != INTEGER_CST |
| || integer_zerop (bottom) |
| || (TYPE_UNSIGNED (type) |
| && (tree_int_cst_sgn (top) < 0 |
| || tree_int_cst_sgn (bottom) < 0))) |
| return 0; |
| return wi::multiple_of_p (wi::to_widest (top), wi::to_widest (bottom), |
| SIGNED); |
| |
| case SSA_NAME: |
| if (TREE_CODE (bottom) == INTEGER_CST |
| && (stmt = SSA_NAME_DEF_STMT (top)) != NULL |
| && gimple_code (stmt) == GIMPLE_ASSIGN) |
| { |
| enum tree_code code = gimple_assign_rhs_code (stmt); |
| |
| /* Check for special cases to see if top is defined as multiple |
| of bottom: |
| |
| top = (X & ~(bottom - 1) ; bottom is power of 2 |
| |
| or |
| |
| Y = X % bottom |
| top = X - Y. */ |
| if (code == BIT_AND_EXPR |
| && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE |
| && TREE_CODE (op2) == INTEGER_CST |
| && integer_pow2p (bottom) |
| && wi::multiple_of_p (wi::to_widest (op2), |
| wi::to_widest (bottom), UNSIGNED)) |
| return 1; |
| |
| op1 = gimple_assign_rhs1 (stmt); |
| if (code == MINUS_EXPR |
| && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE |
| && TREE_CODE (op2) == SSA_NAME |
| && (stmt = SSA_NAME_DEF_STMT (op2)) != NULL |
| && gimple_code (stmt) == GIMPLE_ASSIGN |
| && (code = gimple_assign_rhs_code (stmt)) == TRUNC_MOD_EXPR |
| && operand_equal_p (op1, gimple_assign_rhs1 (stmt), 0) |
| && operand_equal_p (bottom, gimple_assign_rhs2 (stmt), 0)) |
| return 1; |
| } |
| |
| /* fall through */ |
| |
| default: |
| if (POLY_INT_CST_P (top) && poly_int_tree_p (bottom)) |
| return multiple_p (wi::to_poly_widest (top), |
| wi::to_poly_widest (bottom)); |
| |
| return 0; |
| } |
| } |
| |
| /* Return true if expression X cannot be (or contain) a NaN or infinity. |
| This function returns true for integer expressions, and returns |
| false if uncertain. */ |
| |
| bool |
| tree_expr_finite_p (const_tree x) |
| { |
| machine_mode mode = element_mode (x); |
| if (!HONOR_NANS (mode) && !HONOR_INFINITIES (mode)) |
| return true; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return real_isfinite (TREE_REAL_CST_PTR (x)); |
| case COMPLEX_CST: |
| return tree_expr_finite_p (TREE_REALPART (x)) |
| && tree_expr_finite_p (TREE_IMAGPART (x)); |
| case FLOAT_EXPR: |
| return true; |
| case ABS_EXPR: |
| case CONVERT_EXPR: |
| case NON_LVALUE_EXPR: |
| case NEGATE_EXPR: |
| case SAVE_EXPR: |
| return tree_expr_finite_p (TREE_OPERAND (x, 0)); |
| case MIN_EXPR: |
| case MAX_EXPR: |
| return tree_expr_finite_p (TREE_OPERAND (x, 0)) |
| && tree_expr_finite_p (TREE_OPERAND (x, 1)); |
| case COND_EXPR: |
| return tree_expr_finite_p (TREE_OPERAND (x, 1)) |
| && tree_expr_finite_p (TREE_OPERAND (x, 2)); |
| case CALL_EXPR: |
| switch (get_call_combined_fn (x)) |
| { |
| CASE_CFN_FABS: |
| return tree_expr_finite_p (CALL_EXPR_ARG (x, 0)); |
| CASE_CFN_FMAX: |
| CASE_CFN_FMIN: |
| return tree_expr_finite_p (CALL_EXPR_ARG (x, 0)) |
| && tree_expr_finite_p (CALL_EXPR_ARG (x, 1)); |
| default: |
| return false; |
| } |
| |
| default: |
| return false; |
| } |
| } |
| |
| /* Return true if expression X evaluates to an infinity. |
| This function returns false for integer expressions. */ |
| |
| bool |
| tree_expr_infinite_p (const_tree x) |
| { |
| if (!HONOR_INFINITIES (x)) |
| return false; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return real_isinf (TREE_REAL_CST_PTR (x)); |
| case ABS_EXPR: |
| case NEGATE_EXPR: |
| case NON_LVALUE_EXPR: |
| case SAVE_EXPR: |
| return tree_expr_infinite_p (TREE_OPERAND (x, 0)); |
| case COND_EXPR: |
| return tree_expr_infinite_p (TREE_OPERAND (x, 1)) |
| && tree_expr_infinite_p (TREE_OPERAND (x, 2)); |
| default: |
| return false; |
| } |
| } |
| |
| /* Return true if expression X could evaluate to an infinity. |
| This function returns false for integer expressions, and returns |
| true if uncertain. */ |
| |
| bool |
| tree_expr_maybe_infinite_p (const_tree x) |
| { |
| if (!HONOR_INFINITIES (x)) |
| return false; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return real_isinf (TREE_REAL_CST_PTR (x)); |
| case FLOAT_EXPR: |
| return false; |
| case ABS_EXPR: |
| case NEGATE_EXPR: |
| return tree_expr_maybe_infinite_p (TREE_OPERAND (x, 0)); |
| case COND_EXPR: |
| return tree_expr_maybe_infinite_p (TREE_OPERAND (x, 1)) |
| || tree_expr_maybe_infinite_p (TREE_OPERAND (x, 2)); |
| default: |
| return true; |
| } |
| } |
| |
| /* Return true if expression X evaluates to a signaling NaN. |
| This function returns false for integer expressions. */ |
| |
| bool |
| tree_expr_signaling_nan_p (const_tree x) |
| { |
| if (!HONOR_SNANS (x)) |
| return false; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return real_issignaling_nan (TREE_REAL_CST_PTR (x)); |
| case NON_LVALUE_EXPR: |
| case SAVE_EXPR: |
| return tree_expr_signaling_nan_p (TREE_OPERAND (x, 0)); |
| case COND_EXPR: |
| return tree_expr_signaling_nan_p (TREE_OPERAND (x, 1)) |
| && tree_expr_signaling_nan_p (TREE_OPERAND (x, 2)); |
| default: |
| return false; |
| } |
| } |
| |
| /* Return true if expression X could evaluate to a signaling NaN. |
| This function returns false for integer expressions, and returns |
| true if uncertain. */ |
| |
| bool |
| tree_expr_maybe_signaling_nan_p (const_tree x) |
| { |
| if (!HONOR_SNANS (x)) |
| return false; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return real_issignaling_nan (TREE_REAL_CST_PTR (x)); |
| case FLOAT_EXPR: |
| return false; |
| case ABS_EXPR: |
| case CONVERT_EXPR: |
| case NEGATE_EXPR: |
| case NON_LVALUE_EXPR: |
| case SAVE_EXPR: |
| return tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 0)); |
| case MIN_EXPR: |
| case MAX_EXPR: |
| return tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 0)) |
| || tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 1)); |
| case COND_EXPR: |
| return tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 1)) |
| || tree_expr_maybe_signaling_nan_p (TREE_OPERAND (x, 2)); |
| case CALL_EXPR: |
| switch (get_call_combined_fn (x)) |
| { |
| CASE_CFN_FABS: |
| return tree_expr_maybe_signaling_nan_p (CALL_EXPR_ARG (x, 0)); |
| CASE_CFN_FMAX: |
| CASE_CFN_FMIN: |
| return tree_expr_maybe_signaling_nan_p (CALL_EXPR_ARG (x, 0)) |
| || tree_expr_maybe_signaling_nan_p (CALL_EXPR_ARG (x, 1)); |
| default: |
| return true; |
| } |
| default: |
| return true; |
| } |
| } |
| |
| /* Return true if expression X evaluates to a NaN. |
| This function returns false for integer expressions. */ |
| |
| bool |
| tree_expr_nan_p (const_tree x) |
| { |
| if (!HONOR_NANS (x)) |
| return false; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return real_isnan (TREE_REAL_CST_PTR (x)); |
| case NON_LVALUE_EXPR: |
| case SAVE_EXPR: |
| return tree_expr_nan_p (TREE_OPERAND (x, 0)); |
| case COND_EXPR: |
| return tree_expr_nan_p (TREE_OPERAND (x, 1)) |
| && tree_expr_nan_p (TREE_OPERAND (x, 2)); |
| default: |
| return false; |
| } |
| } |
| |
| /* Return true if expression X could evaluate to a NaN. |
| This function returns false for integer expressions, and returns |
| true if uncertain. */ |
| |
| bool |
| tree_expr_maybe_nan_p (const_tree x) |
| { |
| if (!HONOR_NANS (x)) |
| return false; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return real_isnan (TREE_REAL_CST_PTR (x)); |
| case FLOAT_EXPR: |
| return false; |
| case PLUS_EXPR: |
| case MINUS_EXPR: |
| case MULT_EXPR: |
| return !tree_expr_finite_p (TREE_OPERAND (x, 0)) |
| || !tree_expr_finite_p (TREE_OPERAND (x, 1)); |
| case ABS_EXPR: |
| case CONVERT_EXPR: |
| case NEGATE_EXPR: |
| case NON_LVALUE_EXPR: |
| case SAVE_EXPR: |
| return tree_expr_maybe_nan_p (TREE_OPERAND (x, 0)); |
| case MIN_EXPR: |
| case MAX_EXPR: |
| return tree_expr_maybe_nan_p (TREE_OPERAND (x, 0)) |
| || tree_expr_maybe_nan_p (TREE_OPERAND (x, 1)); |
| case COND_EXPR: |
| return tree_expr_maybe_nan_p (TREE_OPERAND (x, 1)) |
| || tree_expr_maybe_nan_p (TREE_OPERAND (x, 2)); |
| case CALL_EXPR: |
| switch (get_call_combined_fn (x)) |
| { |
| CASE_CFN_FABS: |
| return tree_expr_maybe_nan_p (CALL_EXPR_ARG (x, 0)); |
| CASE_CFN_FMAX: |
| CASE_CFN_FMIN: |
| return tree_expr_maybe_nan_p (CALL_EXPR_ARG (x, 0)) |
| || tree_expr_maybe_nan_p (CALL_EXPR_ARG (x, 1)); |
| default: |
| return true; |
| } |
| default: |
| return true; |
| } |
| } |
| |
| /* Return true if expression X could evaluate to -0.0. |
| This function returns true if uncertain. */ |
| |
| bool |
| tree_expr_maybe_real_minus_zero_p (const_tree x) |
| { |
| if (!HONOR_SIGNED_ZEROS (x)) |
| return false; |
| switch (TREE_CODE (x)) |
| { |
| case REAL_CST: |
| return REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (x)); |
| case INTEGER_CST: |
| case FLOAT_EXPR: |
| case ABS_EXPR: |
| return false; |
| case NON_LVALUE_EXPR: |
| case SAVE_EXPR: |
| return tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 0)); |
| case COND_EXPR: |
| return tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 1)) |
| || tree_expr_maybe_real_minus_zero_p (TREE_OPERAND (x, 2)); |
| case CALL_EXPR: |
| switch (get_call_combined_fn (x)) |
| { |
| CASE_CFN_FABS: |
| return false; |
| default: |
| break; |
| } |
| default: |
| break; |
| } |
| /* Ideally !(tree_expr_nonzero_p (X) || tree_expr_nonnegative_p (X)) |
| * but currently those predicates require tree and not const_tree. */ |
| return true; |
| } |
| |
| #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 |
| tree_simple_nonnegative_warnv_p (enum tree_code code, tree type) |
| { |
| if ((TYPE_PRECISION (type) != 1 || TYPE_UNSIGNED (type)) |
| && truth_value_p (code)) |
| /* Truth values evaluate to 0 or 1, which is nonnegative unless we |
| have a signed:1 type (where the value is -1 and 0). */ |
| return true; |
| return false; |
| } |
| |
| /* 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. 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, int depth) |
| { |
| if (TYPE_UNSIGNED (type)) |
| return true; |
| |
| switch (code) |
| { |
| case ABS_EXPR: |
| /* We can't return 1 if flag_wrapv is set because |
| ABS_EXPR<INT_MIN> = INT_MIN. */ |
| if (!ANY_INTEGRAL_TYPE_P (type)) |
| return true; |
| if (TYPE_OVERFLOW_UNDEFINED (type)) |
| { |
| *strict_overflow_p = true; |
| return true; |
| } |
| break; |
| |
| case NON_LVALUE_EXPR: |
| case FLOAT_EXPR: |
| case FIX_TRUNC_EXPR: |
| return RECURSE (op0); |
| |
| CASE_CONVERT: |
| { |
| tree inner_type = TREE_TYPE (op0); |
| tree outer_type = type; |
| |
| if (TREE_CODE (outer_type) == REAL_TYPE) |
| { |
| if (TREE_CODE (inner_type) == REAL_TYPE) |
| return RECURSE (op0); |
| if (INTEGRAL_TYPE_P (inner_type)) |
| { |
| if (TYPE_UNSIGNED (inner_type)) |
| return true; |
| return RECURSE (op0); |
| } |
| } |
| else if (INTEGRAL_TYPE_P (outer_type)) |
| { |
| if (TREE_CODE (inner_type) == REAL_TYPE) |
| return RECURSE (op0); |
| if (INTEGRAL_TYPE_P (inner_type)) |
| return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type) |
| && TYPE_UNSIGNED (inner_type); |
| } |
| } |
| break; |
| |
| default: |
| return tree_simple_nonnegative_warnv_p (code, type); |
| } |
| |
| /* We don't know sign of `t', so be conservative and return false. */ |
| return false; |
| } |
| |
| /* 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. 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, |
| int depth) |
| { |
| if (TYPE_UNSIGNED (type)) |
| return true; |
| |
| switch (code) |
| { |
| case POINTER_PLUS_EXPR: |
| case PLUS_EXPR: |
| if (FLOAT_TYPE_P (type)) |
| 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. */ |
| if (TREE_CODE (type) == INTEGER_TYPE |
| && TREE_CODE (op0) == NOP_EXPR |
| && TREE_CODE (op1) == NOP_EXPR) |
| { |
| tree inner1 = TREE_TYPE (TREE_OPERAND (op0, 0)); |
| tree inner2 = TREE_TYPE (TREE_OPERAND (op1, 0)); |
| if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1) |
| && TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2)) |
| { |
| unsigned int prec = MAX (TYPE_PRECISION (inner1), |
| TYPE_PRECISION (inner2)) + 1; |
| return prec < TYPE_PRECISION (type); |
| } |
| } |
| break; |
| |
| case MULT_EXPR: |
| if (FLOAT_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) |
| { |
| /* x * x is always non-negative for floating point x |
| or without overflow. */ |
| if (operand_equal_p (op0, op1, 0) |
| || (RECURSE (op0) && RECURSE (op1))) |
| { |
| if (ANY_INTEGRAL_TYPE_P (type) |
| && TYPE_OVERFLOW_UNDEFINED (type)) |
| *strict_overflow_p = true; |
| return true; |
| } |
| } |
| |
| /* zero_extend(x) * zero_extend(y) is non-negative if x and y are |
| both unsigned and their total bits is shorter than the result. */ |
| if (TREE_CODE (type) == INTEGER_TYPE |
| && (TREE_CODE (op0) == NOP_EXPR || TREE_CODE (op0) == INTEGER_CST) |
| && (TREE_CODE (op1) == NOP_EXPR || TREE_CODE (op1) == INTEGER_CST)) |
| { |
| tree inner0 = (TREE_CODE (op0) == NOP_EXPR) |
| ? TREE_TYPE (TREE_OPERAND (op0, 0)) |
| : TREE_TYPE (op0); |
| tree inner1 = (TREE_CODE (op1) == NOP_EXPR) |
| ? TREE_TYPE (TREE_OPERAND (op1, 0)) |
| : TREE_TYPE (op1); |
| |
| bool unsigned0 = TYPE_UNSIGNED (inner0); |
| bool unsigned1 = TYPE_UNSIGNED (inner1); |
| |
| if (TREE_CODE (op0) == INTEGER_CST) |
| unsigned0 = unsigned0 || tree_int_cst_sgn (op0) >= 0; |
| |
| if (TREE_CODE (op1) == INTEGER_CST) |
| unsigned1 = unsigned1 || tree_int_cst_sgn (op1) >= 0; |
| |
| if (TREE_CODE (inner0) == INTEGER_TYPE && unsigned0 |
| && TREE_CODE (inner1) == INTEGER_TYPE && unsigned1) |
| { |
| unsigned int precision0 = (TREE_CODE (op0) == INTEGER_CST) |
| ? tree_int_cst_min_precision (op0, UNSIGNED) |
| : TYPE_PRECISION (inner0); |
| |
| unsigned int precision1 = (TREE_CODE (op1) == INTEGER_CST) |
| ? tree_int_cst_min_precision (op1, UNSIGNED) |
| : TYPE_PRECISION (inner1); |
| |
| return precision0 + precision1 < TYPE_PRECISION (type); |
| } |
| } |
| return false; |
| |
| case BIT_AND_EXPR: |
| return RECURSE (op0) || RECURSE (op1); |
| |
| case MAX_EXPR: |
| /* Usually RECURSE (op0) || RECURSE (op1) but NaNs complicate |
| things. */ |
| if (tree_expr_maybe_nan_p (op0) || tree_expr_maybe_nan_p (op1)) |
| return RECURSE (op0) && RECURSE (op1); |
| return RECURSE (op0) || RECURSE (op1); |
| |
| case BIT_IOR_EXPR: |
| case BIT_XOR_EXPR: |
| case MIN_EXPR: |
| case RDIV_EXPR: |
| case TRUNC_DIV_EXPR: |
| case CEIL_DIV_EXPR: |
| case FLOOR_DIV_EXPR: |
| case ROUND_DIV_EXPR: |
| return RECURSE (op0) && RECURSE (op1); |
| |
| case TRUNC_MOD_EXPR: |
| return RECURSE (op0); |
| |
| case FLOOR_MOD_EXPR: |
| return RECURSE (op1); |
| |
| case CEIL_MOD_EXPR: |
| case ROUND_MOD_EXPR: |
| default: |
| return tree_simple_nonnegative_warnv_p (code, type); |
| } |
| |
| /* 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. DEPTH is the current nesting depth of the query. */ |
| |
| bool |
| tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth) |
| { |
| if (TYPE_UNSIGNED (TREE_TYPE (t))) |
| return true; |
| |
| switch (TREE_CODE (t)) |
| { |
| case INTEGER_CST: |
| return tree_int_cst_sgn (t) >= 0; |
| |
| case REAL_CST: |
| return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)); |
| |
| case FIXED_CST: |
| return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (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_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 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. DEPTH is the current nesting depth of the query. */ |
| |
| bool |
| tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1, |
| bool *strict_overflow_p, int depth) |
| { |
| switch (fn) |
| { |
| CASE_CFN_ACOS: |
| CASE_CFN_ACOSH: |
| CASE_CFN_CABS: |
| CASE_CFN_COSH: |
| CASE_CFN_ERFC: |
| CASE_CFN_EXP: |
| CASE_CFN_EXP10: |
| CASE_CFN_EXP2: |
| CASE_CFN_FABS: |
| CASE_CFN_FDIM: |
| CASE_CFN_HYPOT: |
| CASE_CFN_POW10: |
| CASE_CFN_FFS: |
| CASE_CFN_PARITY: |
| CASE_CFN_POPCOUNT: |
| CASE_CFN_CLZ: |
| CASE_CFN_CLRSB: |
| case CFN_BUILT_IN_BSWAP16: |
| case CFN_BUILT_IN_BSWAP32: |
| case CFN_BUILT_IN_BSWAP64: |
| case CFN_BUILT_IN_BSWAP128: |
| /* Always true. */ |
| return true; |
| |
| CASE_CFN_SQRT: |
| CASE_CFN_SQRT_FN: |
| /* sqrt(-0.0) is -0.0. */ |
| if (!HONOR_SIGNED_ZEROS (type)) |
| return true; |
| return RECURSE (arg0); |
| |
| CASE_CFN_ASINH: |
| CASE_CFN_ATAN: |
| CASE_CFN_ATANH: |
| CASE_CFN_CBRT: |
| CASE_CFN_CEIL: |
| CASE_CFN_CEIL_FN: |
| CASE_CFN_ERF: |
| CASE_CFN_EXPM1: |
| CASE_CFN_FLOOR: |
| CASE_CFN_FLOOR_FN: |
| CASE_CFN_FMOD: |
| CASE_CFN_FREXP: |
| CASE_CFN_ICEIL: |
| CASE_CFN_IFLOOR: |
| CASE_CFN_IRINT: |
| CASE_CFN_IROUND: |
| CASE_CFN_LCEIL: |
| CASE_CFN_LDEXP: |
| CASE_CFN_LFLOOR: |
| CASE_CFN_LLCEIL: |
| CASE_CFN_LLFLOOR: |
| CASE_CFN_LLRINT: |
| CASE_CFN_LLROUND: |
| CASE_CFN_LRINT: |
| CASE_CFN_LROUND: |
| CASE_CFN_MODF: |
| CASE_CFN_NEARBYINT: |
| CASE_CFN_NEARBYINT_FN: |
| CASE_CFN_RINT: |
| CASE_CFN_RINT_FN: |
| CASE_CFN_ROUND: |
| CASE_CFN_ROUND_FN: |
| CASE_CFN_ROUNDEVEN: |
| CASE_CFN_ROUNDEVEN_FN: |
| CASE_CFN_SCALB: |
| CASE_CFN_SCALBLN: |
| CASE_CFN_SCALBN: |
| CASE_CFN_SIGNBIT: |
| CASE_CFN_SIGNIFICAND: |
| CASE_CFN_SINH: |
| CASE_CFN_TANH: |
| CASE_CFN_TRUNC: |
| CASE_CFN_TRUNC_FN: |
| /* True if the 1st argument is nonnegative. */ |
| return RECURSE (arg0); |
| |
| CASE_CFN_FMAX: |
| CASE_CFN_FMAX_FN: |
| /* Usually RECURSE (arg0) || RECURSE (arg1) but NaNs complicate |
| things. In the presence of sNaNs, we're only guaranteed to be |
| non-negative if both operands are non-negative. In the presence |
| of qNaNs, we're non-negative if either operand is non-negative |
| and can't be a qNaN, or if both operands are non-negative. */ |
| if (tree_expr_maybe_signaling_nan_p (arg0) || |
| tree_expr_maybe_signaling_nan_p (arg1)) |
| return RECURSE (arg0) && RECURSE (arg1); |
| return RECURSE (arg0) ? (!tree_expr_maybe_nan_p (arg0) |
| || RECURSE (arg1)) |
| : (RECURSE (arg1) |
| && !tree_expr_maybe_nan_p (arg1)); |
| |
| CASE_CFN_FMIN: |
| CASE_CFN_FMIN_FN: |
| /* True if the 1st AND 2nd arguments are nonnegative. */ |
| return RECURSE (arg0) && RECURSE (arg1); |
| |
| CASE_CFN_COPYSIGN: |
| CASE_CFN_COPYSIGN_FN: |
| /* True if the 2nd argument is nonnegative. */ |
| return RECURSE (arg1); |
| |
| CASE_CFN_POWI: |
| /* True if the 1st argument is nonnegative or the second |
| argument is an even integer. */ |
| if (TREE_CODE (arg1) == INTEGER_CST |
| && (TREE_INT_CST_LOW (arg1) & 1) == 0) |
| return true; |
| return RECURSE (arg0); |
| |
| CASE_CFN_POW: |
| /* True if the 1st argument is nonnegative or the second |
| argument is an even integer valued real. */ |
| if (TREE_CODE (arg1) == REAL_CST) |
| { |
| REAL_VALUE_TYPE c; |
| HOST_WIDE_INT n; |
| |
| c = TREE_REAL_CST (arg1); |
| n = real_to_integer (&c); |
| if ((n & 1) == 0) |
| { |
| REAL_VALUE_TYPE cint; |
| real_from_integer (&cint, VOIDmode, n, SIGNED); |
| if (real_identical (&c, &cint)) |
| return true; |
| } |
| } |
| return RECURSE (arg0); |
| |
| default: |
| break; |
| } |
| 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. DEPTH is the current nesting depth of the query. */ |
| |
| static bool |
| 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))) |
| return true; |
| |
| switch (code) |
| { |
| case TARGET_EXPR: |
| { |
| tree temp = TARGET_EXPR_SLOT (t); |
| t = TARGET_EXPR_INITIAL (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 RECURSE (t); |
| |
| /* Otherwise, the initializer sets the slot in some way. One common |
| way is an assignment statement at the end of the initializer. */ |
| while (1) |
| { |
| if (TREE_CODE (t) == BIND_EXPR) |
| t = expr_last (BIND_EXPR_BODY (t)); |
| else if (TREE_CODE (t) == TRY_FINALLY_EXPR |
| || TREE_CODE (t) == TRY_CATCH_EXPR) |
| t = expr_last (TREE_OPERAND (t, 0)); |
| else if (TREE_CODE (t) == STATEMENT_LIST) |
| t = expr_last (t); |
| else |
| break; |
| } |
| if (TREE_CODE (t) == MODIFY_EXPR |
| && TREE_OPERAND (t, 0) == temp) |
| return RECURSE (TREE_OPERAND (t, 1)); |
| |
| return false; |
| } |
| |
| 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 tree_call_nonnegative_warnv_p (TREE_TYPE (t), |
| get_call_combined_fn (t), |
| arg0, |
| arg1, |
| strict_overflow_p, depth); |
| } |
| case COMPOUND_EXPR: |
| case MODIFY_EXPR: |
| return RECURSE (TREE_OPERAND (t, 1)); |
| |
| case BIND_EXPR: |
| return RECURSE (expr_last (TREE_OPERAND (t, 1))); |
| |
| case SAVE_EXPR: |
| return RECURSE (TREE_OPERAND (t, 0)); |
| |
| default: |
| return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t)); |
| } |
| } |
| |
| #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. DEPTH is the current nesting depth of the query. */ |
| |
| bool |
| tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth) |
| { |
| enum tree_code code; |
| if (t == error_mark_node) |
| return false; |
| |
|