X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Ffold-const.c;h=804a05f927a0a432a90bc234cbfe5ab316f29b28;hp=dcd6989b285522e50603334e9c6a5fc7eed7ea20;hb=9d6f975807ff20c6d426b452e15a684d0815122c;hpb=b1757d46a6ec2a81b4e2cb78df5ec3e2e5567d5e diff --git a/gcc/fold-const.c b/gcc/fold-const.c index dcd6989b285..804a05f927a 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -1,7 +1,7 @@ /* Fold a constant sub-tree into a single node for C-compiler Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -112,16 +112,13 @@ static tree decode_field_reference (location_t, tree, HOST_WIDE_INT *, static int all_ones_mask_p (const_tree, int); static tree sign_bit_p (tree, const_tree); static int 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); -extern tree make_range (tree, int *, tree *, tree *, bool *); -extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int, - tree, tree); static tree fold_range_test (location_t, enum tree_code, tree, tree, tree); static tree fold_cond_expr_with_comparison (location_t, tree, tree, tree, tree); static tree unextend (tree, int, int, tree); -static tree fold_truthop (location_t, enum tree_code, tree, tree, tree); static tree optimize_minmax_comparison (location_t, enum tree_code, tree, tree, tree); static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); @@ -489,11 +486,24 @@ negate_expr_p (tree t) and actually traps on some architectures. But if overflow is undefined, we can negate, because - (INT_MIN / 1) is an overflow. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (t)) - && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))) - break; - return negate_expr_p (TREE_OPERAND (t, 1)) - || negate_expr_p (TREE_OPERAND (t, 0)); + if (INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + if (!TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))) + break; + /* If overflow is undefined then we have to be careful because + we ask whether it's ok to associate the negate with the + division which is not ok for example for + -((a - b) / c) where (-(a - b)) / c may invoke undefined + overflow because of negating INT_MIN. So do not use + negate_expr_p here but open-code the two important cases. */ + if (TREE_CODE (TREE_OPERAND (t, 0)) == NEGATE_EXPR + || (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST + && may_negate_without_overflow_p (TREE_OPERAND (t, 0)))) + return true; + } + else if (negate_expr_p (TREE_OPERAND (t, 0))) + return true; + return negate_expr_p (TREE_OPERAND (t, 1)); case NOP_EXPR: /* Negate -((double)float) as (double)(-float). */ @@ -673,16 +683,20 @@ fold_negate_expr (location_t loc, tree t) return fold_build2_loc (loc, TREE_CODE (t), type, TREE_OPERAND (t, 0), negate_expr (tem)); } + /* If overflow is undefined then we have to be careful because + we ask whether it's ok to associate the negate with the + division which is not ok for example for + -((a - b) / c) where (-(a - b)) / c may invoke undefined + overflow because of negating INT_MIN. So do not use + negate_expr_p here but open-code the two important cases. */ tem = TREE_OPERAND (t, 0); - if (negate_expr_p (tem)) - { - if (INTEGRAL_TYPE_P (type) - && (TREE_CODE (tem) != INTEGER_CST - || tree_int_cst_equal (tem, TYPE_MIN_VALUE (type)))) - fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC); - return fold_build2_loc (loc, TREE_CODE (t), type, - negate_expr (tem), TREE_OPERAND (t, 1)); - } + if ((INTEGRAL_TYPE_P (type) + && (TREE_CODE (tem) == NEGATE_EXPR + || (TREE_CODE (tem) == INTEGER_CST + && may_negate_without_overflow_p (tem)))) + || !INTEGRAL_TYPE_P (type)) + return fold_build2_loc (loc, TREE_CODE (t), type, + negate_expr (tem), TREE_OPERAND (t, 1)); } break; @@ -1867,9 +1881,6 @@ fold_convert_loc (location_t loc, tree type, tree arg) || TREE_CODE (orig) == ERROR_MARK) return error_mark_node; - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig)) - return fold_build1_loc (loc, NOP_EXPR, type, arg); - switch (TREE_CODE (type)) { case POINTER_TYPE: @@ -2017,6 +2028,8 @@ fold_convert_loc (location_t loc, tree type, tree 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: @@ -2104,15 +2117,14 @@ pedantic_non_lvalue_loc (location_t loc, tree x) return protected_set_expr_location_unshare (x, loc); } -/* Given a tree comparison code, return the code that is the logical inverse - of the given code. It is not safe to do this for floating-point - comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode - as well: if reversing the comparison is unsafe, return ERROR_MARK. */ +/* 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 and NE_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) + if (honor_nans && flag_trapping_math && code != EQ_EXPR && code != NE_EXPR) return ERROR_MARK; switch (code) @@ -3504,7 +3516,7 @@ optimize_bit_field_compare (location_t loc, enum tree_code code, return lhs; } -/* Subroutine for fold_truthop: decode a field reference. +/* Subroutine for fold_truth_andor_1: decode a field reference. If EXP is a comparison reference, we return the innermost reference. @@ -3672,7 +3684,7 @@ sign_bit_p (tree exp, const_tree val) return NULL_TREE; } -/* Subroutine for fold_truthop: determine if an operand is simple enough +/* Subroutine for fold_truth_andor_1: determine if an operand is simple enough to be evaluated unconditionally. */ static int @@ -3682,7 +3694,7 @@ simple_operand_p (const_tree exp) STRIP_NOPS (exp); return (CONSTANT_CLASS_P (exp) - || TREE_CODE (exp) == SSA_NAME + || TREE_CODE (exp) == SSA_NAME || (DECL_P (exp) && ! TREE_ADDRESSABLE (exp) && ! TREE_THIS_VOLATILE (exp) @@ -3696,6 +3708,36 @@ simple_operand_p (const_tree exp) 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) + || tree_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. @@ -3791,288 +3833,323 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p, return constant_boolean_node (result, type); } -/* 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. */ +/* 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 (tree exp, int *pin_p, tree *plow, tree *phigh, - bool *strict_overflow_p) +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) { - enum tree_code code; - tree arg0 = NULL_TREE, arg1 = NULL_TREE; - tree exp_type = NULL_TREE, arg0_type = NULL_TREE; - int in_p, n_in_p; - tree low, high, n_low, n_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); + 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; - while (1) + switch (code) { - code = TREE_CODE (exp); - exp_type = TREE_TYPE (exp); + 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; - if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) + switch (code) { - if (TREE_OPERAND_LENGTH (exp) > 0) - arg0 = TREE_OPERAND (exp, 0); - if (TREE_CODE_CLASS (code) == tcc_comparison - || TREE_CODE_CLASS (code) == tcc_unary - || TREE_CODE_CLASS (code) == tcc_binary) - arg0_type = TREE_TYPE (arg0); - 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); + 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 (); } - switch (code) + /* 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)) { - case TRUTH_NOT_EXPR: - in_p = ! in_p, exp = arg0; - continue; - - 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 == 0 || high == 0 - || ! integer_zerop (low) || ! integer_zerop (high) - || TREE_CODE (arg1) != INTEGER_CST) - break; + 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; - 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 (); - } + in_p = n_in_p, low = n_low, high = n_high; - /* 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 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)) { - if (! merge_ranges (&n_in_p, &n_low, &n_high, - in_p, low, high, 1, - build_int_cst (arg0_type, 0), - NULL_TREE)) - break; - - 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, - integer_one_node, 0); - low = build_int_cst (arg0_type, 0); - } + in_p = ! in_p; + high = range_binop (MINUS_EXPR, NULL_TREE, low, 0, + integer_one_node, 0); + low = build_int_cst (arg0_type, 0); } + } - exp = arg0; - continue; - - case NEGATE_EXPR: - /* (-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)) - break; - goto normalize; - - case BIT_NOT_EXPR: - /* ~ X -> -X - 1 */ - exp = build2_loc (loc, MINUS_EXPR, exp_type, negate_expr (arg0), - build_int_cst (exp_type, 1)); - continue; + *p_low = low; + *p_high = high; + *p_in_p = in_p; + return arg0; - case PLUS_EXPR: case MINUS_EXPR: - if (TREE_CODE (arg1) != INTEGER_CST) - break; + 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; - /* 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)) - break; + case BIT_NOT_EXPR: + /* ~ X -> -X - 1 */ + return build2_loc (loc, MINUS_EXPR, exp_type, negate_expr (arg0), + build_int_cst (exp_type, 1)); - /* 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))) - break; + case PLUS_EXPR: + case MINUS_EXPR: + if (TREE_CODE (arg1) != INTEGER_CST) + return NULL_TREE; - if (TYPE_OVERFLOW_UNDEFINED (arg0_type)) - *strict_overflow_p = true; + /* 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; - 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, - integer_one_node, 0); - high = range_binop (MINUS_EXPR, arg0_type, n_low, 0, - integer_one_node, 0); + /* 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 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; + if (TYPE_OVERFLOW_UNDEFINED (arg0_type)) + *strict_overflow_p = true; - exp = arg0; - continue; + 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, + integer_one_node, 0); + high = range_binop (MINUS_EXPR, arg0_type, n_low, 0, + integer_one_node, 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; - CASE_CONVERT: case NON_LVALUE_EXPR: - if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type)) - break; + *p_low = low; + *p_high = high; + *p_in_p = in_p; + return arg0; - if (! INTEGRAL_TYPE_P (arg0_type) - || (low != 0 && ! int_fits_type_p (low, arg0_type)) - || (high != 0 && ! int_fits_type_p (high, arg0_type))) - break; + CASE_CONVERT: + case NON_LVALUE_EXPR: + if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type)) + return NULL_TREE; - n_low = low, n_high = high; + 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; - if (n_low != 0) - n_low = fold_convert_loc (loc, arg0_type, n_low); + n_low = low, n_high = high; - if (n_high != 0) - n_high = fold_convert_loc (loc, arg0_type, n_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. + /* 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. */ + 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, + 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)) - break; + /* 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)) - break; + 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); - } + in_p = (in_p != n_in_p); } + } - exp = arg0; - low = n_low, high = n_high; - continue; + *p_low = n_low; + *p_high = n_high; + *p_in_p = in_p; + return arg0; - default: - break; + 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; - 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. */ @@ -4872,7 +4949,7 @@ fold_range_test (location_t loc, enum tree_code code, tree type, return 0; } -/* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P +/* 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. */ @@ -5009,8 +5086,8 @@ merge_truthop_with_opposite_arm (location_t loc, tree op, tree cmpop, We return the simplified tree or 0 if no optimization is possible. */ static tree -fold_truthop (location_t loc, enum tree_code code, tree truth_type, - tree lhs, tree rhs) +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 @@ -5038,8 +5115,6 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type, tree lntype, rntype, result; HOST_WIDE_INT first_bit, end_bit; int volatilep; - tree orig_lhs = lhs, orig_rhs = rhs; - enum tree_code orig_code = code; /* 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 @@ -5103,8 +5178,7 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type, /* 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. Avoid doing this if the RHS is a floating-point - comparison since those can trap. */ + that can be merged. */ if (BRANCH_COST (optimize_function_for_speed_p (cfun), false) >= 2 @@ -5133,13 +5207,6 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type, build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg), ll_arg, rl_arg), build_int_cst (TREE_TYPE (ll_arg), 0)); - - if (LOGICAL_OP_NON_SHORT_CIRCUIT) - { - if (code != orig_code || lhs != orig_lhs || rhs != orig_rhs) - return build2_loc (loc, code, truth_type, lhs, rhs); - return NULL_TREE; - } } /* See if the comparisons can be merged. Then get all the parameters for @@ -5666,6 +5733,11 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type, 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)); @@ -5929,17 +6001,22 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type, } /* Return a node which has the indicated constant VALUE (either 0 or - 1), and is of the indicated TYPE. */ + 1 for scalars or {-1,-1,..} or {0,0,...} for vectors), + and is of the indicated TYPE. */ tree -constant_boolean_node (int value, tree type) +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 build_int_cst (type, value); + return fold_convert (type, value ? integer_one_node : integer_zero_node); } @@ -5986,10 +6063,11 @@ fold_binary_op_with_conditional_arg (location_t loc, } /* This transformation is only worthwhile if we don't have to wrap ARG - in a SAVE_EXPR and the operation can be simplified on at least one - of the branches once its pushed inside the COND_EXPR. */ + 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; @@ -6741,12 +6819,14 @@ fold_sign_changed_comparison (location_t loc, enum tree_code code, tree type, && TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type)) return NULL_TREE; - if ((TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type) - || POINTER_TYPE_P (inner_type) != POINTER_TYPE_P (outer_type)) + if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type) && code != NE_EXPR && code != EQ_EXPR) return NULL_TREE; + if (POINTER_TYPE_P (inner_type) != POINTER_TYPE_P (outer_type)) + return NULL_TREE; + if (TREE_CODE (arg1) == INTEGER_CST) arg1 = force_fit_type_double (inner_type, tree_to_double_int (arg1), 0, TREE_OVERFLOW (arg1)); @@ -6810,6 +6890,78 @@ try_move_mult_to_index (location_t loc, tree addr, tree op1) s = integer_one_node; } + /* Handle &x.array the same as we would handle &x.array[0]. */ + if (TREE_CODE (ref) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE) + { + tree domain; + + /* Remember if this was a multi-dimensional array. */ + if (TREE_CODE (TREE_OPERAND (ref, 0)) == ARRAY_REF) + mdim = true; + + domain = TYPE_DOMAIN (TREE_TYPE (ref)); + if (! domain) + goto cont; + itype = TREE_TYPE (domain); + + step = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ref))); + if (TREE_CODE (step) != INTEGER_CST) + goto cont; + + if (s) + { + if (! tree_int_cst_equal (step, s)) + goto cont; + } + else + { + /* Try if delta is a multiple of step. */ + tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, op1, step); + if (! tmp) + goto cont; + delta = tmp; + } + + /* Only fold here if we can verify we do not overflow one + dimension of a multi-dimensional array. */ + if (mdim) + { + tree tmp; + + if (!TYPE_MIN_VALUE (domain) + || !TYPE_MAX_VALUE (domain) + || TREE_CODE (TYPE_MAX_VALUE (domain)) != INTEGER_CST) + goto cont; + + tmp = fold_binary_loc (loc, PLUS_EXPR, itype, + fold_convert_loc (loc, itype, + TYPE_MIN_VALUE (domain)), + fold_convert_loc (loc, itype, delta)); + if (TREE_CODE (tmp) != INTEGER_CST + || tree_int_cst_lt (TYPE_MAX_VALUE (domain), tmp)) + goto cont; + } + + /* We found a suitable component reference. */ + + pref = TREE_OPERAND (addr, 0); + ret = copy_node (pref); + SET_EXPR_LOCATION (ret, loc); + + ret = build4_loc (loc, ARRAY_REF, TREE_TYPE (TREE_TYPE (ref)), ret, + fold_build2_loc + (loc, PLUS_EXPR, itype, + fold_convert_loc (loc, itype, + TYPE_MIN_VALUE + (TYPE_DOMAIN (TREE_TYPE (ref)))), + fold_convert_loc (loc, itype, delta)), + NULL_TREE, NULL_TREE); + return build_fold_addr_expr_loc (loc, ret); + } + +cont: + for (;; ref = TREE_OPERAND (ref, 0)) { if (TREE_CODE (ref) == ARRAY_REF) @@ -6888,11 +7040,10 @@ try_move_mult_to_index (location_t loc, tree addr, tree op1) pos = TREE_OPERAND (pos, 0); } - TREE_OPERAND (pos, 1) = fold_build2_loc (loc, PLUS_EXPR, itype, - fold_convert_loc (loc, itype, - TREE_OPERAND (pos, 1)), - fold_convert_loc (loc, itype, delta)); - + TREE_OPERAND (pos, 1) + = fold_build2_loc (loc, PLUS_EXPR, itype, + fold_convert_loc (loc, itype, TREE_OPERAND (pos, 1)), + fold_convert_loc (loc, itype, delta)); return fold_build1_loc (loc, ADDR_EXPR, TREE_TYPE (addr), ret); } @@ -7540,6 +7691,8 @@ build_fold_addr_expr_loc (location_t loc, tree t) return build_fold_addr_expr_with_type_loc (loc, t, ptrtype); } +static bool vec_cst_ctor_to_array (tree, tree *); + /* 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. */ @@ -7668,8 +7821,8 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) TREE_OPERAND (op0, 1)); else if (!INTEGRAL_TYPE_P (type)) return build3_loc (loc, COND_EXPR, type, op0, - fold_convert (type, boolean_true_node), - fold_convert (type, boolean_false_node)); + constant_boolean_node (true, type), + constant_boolean_node (false, type)); } /* Handle cases of two conversions in a row. */ @@ -7854,6 +8007,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) that this happens when X or Y is NOP_EXPR or Y is INTEGER_CST. */ if (POINTER_TYPE_P (type) && TREE_CODE (arg0) == POINTER_PLUS_EXPR + && (!TYPE_RESTRICT (type) || TYPE_RESTRICT (TREE_TYPE (arg0))) && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST || TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR || TREE_CODE (TREE_OPERAND (arg0, 1)) == NOP_EXPR)) @@ -8182,6 +8336,44 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) } return NULL_TREE; + case VEC_UNPACK_LO_EXPR: + case VEC_UNPACK_HI_EXPR: + case VEC_UNPACK_FLOAT_LO_EXPR: + case VEC_UNPACK_FLOAT_HI_EXPR: + { + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + tree *elts, vals = NULL_TREE; + enum tree_code subcode; + + gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts * 2); + if (TREE_CODE (arg0) != VECTOR_CST) + return NULL_TREE; + + elts = XALLOCAVEC (tree, nelts * 2); + if (!vec_cst_ctor_to_array (arg0, elts)) + return NULL_TREE; + + if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_UNPACK_LO_EXPR + || code == VEC_UNPACK_FLOAT_LO_EXPR)) + elts += nelts; + + if (code == VEC_UNPACK_LO_EXPR || code == VEC_UNPACK_HI_EXPR) + subcode = NOP_EXPR; + else + subcode = FLOAT_EXPR; + + for (i = 0; i < nelts; i++) + { + elts[i] = fold_convert_const (subcode, TREE_TYPE (type), elts[i]); + if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i])) + return NULL_TREE; + } + + for (i = 0; i < nelts; i++) + vals = tree_cons (NULL_TREE, elts[nelts - i - 1], vals); + return build_vector (type, vals); + } + default: return NULL_TREE; } /* switch (code) */ @@ -8287,13 +8479,69 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type, 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 - && 0 != (tem = fold_truthop (loc, code, type, - TREE_OPERAND (arg0, 1), arg1))) + && 0 != (tem = fold_truth_andor_1 (loc, code, type, + TREE_OPERAND (arg0, 1), arg1))) return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem); - if ((tem = fold_truthop (loc, code, type, arg0, arg1)) != 0) + if ((tem = fold_truth_andor_1 (loc, code, type, arg0, arg1)) != 0) return tem; + if ((BRANCH_COST (optimize_function_for_speed_p (cfun), + false) >= 2) + && LOGICAL_OP_NON_SHORT_CIRCUIT + && (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 abouve 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; } @@ -8678,6 +8926,17 @@ fold_comparison (location_t loc, enum tree_code code, tree type, indirect_base0 = true; } offset0 = TREE_OPERAND (arg0, 1); + if (host_integerp (offset0, 0)) + { + HOST_WIDE_INT off = size_low_cst (offset0); + if ((HOST_WIDE_INT) (((unsigned HOST_WIDE_INT) off) + * BITS_PER_UNIT) + / BITS_PER_UNIT == (HOST_WIDE_INT) off) + { + bitpos0 = off * BITS_PER_UNIT; + offset0 = NULL_TREE; + } + } } base1 = arg1; @@ -8701,6 +8960,17 @@ fold_comparison (location_t loc, enum tree_code code, tree type, indirect_base1 = true; } offset1 = TREE_OPERAND (arg1, 1); + if (host_integerp (offset1, 0)) + { + HOST_WIDE_INT off = size_low_cst (offset1); + if ((HOST_WIDE_INT) (((unsigned HOST_WIDE_INT) off) + * BITS_PER_UNIT) + / BITS_PER_UNIT == (HOST_WIDE_INT) off) + { + bitpos1 = off * BITS_PER_UNIT; + offset1 = NULL_TREE; + } + } } /* A local variable can never be pointed to by @@ -8738,6 +9008,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type, && operand_equal_p (offset0, offset1, 0))) && (code == EQ_EXPR || code == NE_EXPR + || (indirect_base0 && DECL_P (base0)) || POINTER_TYPE_OVERFLOW_UNDEFINED)) { @@ -8777,6 +9048,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type, 6.5.6/8 and /9 with respect to the signed ptrdiff_t. */ else if (bitpos0 == bitpos1 && ((code == EQ_EXPR || code == NE_EXPR) + || (indirect_base0 && DECL_P (base0)) || POINTER_TYPE_OVERFLOW_UNDEFINED)) { /* By converting to signed size type we cover middle-end pointer @@ -9358,6 +9630,124 @@ get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue, return 1; } +/* Helper function for fold_vec_perm. Store elements of VECTOR_CST or + CONSTRUCTOR ARG into array ELTS and return true if successful. */ + +static bool +vec_cst_ctor_to_array (tree arg, tree *elts) +{ + unsigned int nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)), i; + + if (TREE_CODE (arg) == VECTOR_CST) + { + tree t; + + for (i = 0, t = TREE_VECTOR_CST_ELTS (arg); + i < nelts && t; i++, t = TREE_CHAIN (t)) + elts[i] = TREE_VALUE (t); + if (t) + return false; + } + else if (TREE_CODE (arg) == CONSTRUCTOR) + { + constructor_elt *elt; + + FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (arg), i, elt) + if (i >= nelts) + 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. */ + +static tree +fold_vec_perm (tree type, tree arg0, tree arg1, const unsigned char *sel) +{ + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + tree *elts; + bool need_ctor = false; + + gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts + && 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; + + elts = XALLOCAVEC (tree, nelts * 3); + if (!vec_cst_ctor_to_array (arg0, elts) + || !vec_cst_ctor_to_array (arg1, elts + nelts)) + return NULL_TREE; + + for (i = 0; i < nelts; i++) + { + if (!CONSTANT_CLASS_P (elts[sel[i]])) + need_ctor = true; + elts[i + 2 * nelts] = unshare_expr (elts[sel[i]]); + } + + if (need_ctor) + { + VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, nelts); + for (i = 0; i < nelts; i++) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elts[2 * nelts + i]); + return build_constructor (type, v); + } + else + { + tree vals = NULL_TREE; + for (i = 0; i < nelts; i++) + vals = tree_cons (NULL_TREE, elts[3 * nelts - i - 1], vals); + return build_vector (type, vals); + } +} + +/* 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) +{ + 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))) + || (INDIRECT_REF_P (base0) + && INDIRECT_REF_P (base1) + && (base_offset = fold_binary_loc (loc, MINUS_EXPR, type, + TREE_OPERAND (base0, 0), + TREE_OPERAND (base1, 0)))) + || operand_equal_p (base0, base1, 0)) + { + 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 = build2 (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; +} /* Fold a binary expression of code CODE and type TYPE with operands OP0 and OP1. LOC is the location of the resulting expression. @@ -9672,12 +10062,15 @@ fold_binary_loc (location_t loc, } } - /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the - same or one. Make sure type is not saturating. - fold_plusminus_mult_expr will re-associate. */ + /* 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); @@ -10270,19 +10663,11 @@ fold_binary_loc (location_t loc, && TREE_CODE (arg1) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF) { - tree aref0 = TREE_OPERAND (arg0, 0); - tree aref1 = TREE_OPERAND (arg1, 0); - if (operand_equal_p (TREE_OPERAND (aref0, 0), - TREE_OPERAND (aref1, 0), 0)) - { - tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1)); - tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1)); - tree esz = array_ref_element_size (aref0); - tree diff = build2 (MINUS_EXPR, type, op0, op1); - return fold_build2_loc (loc, MULT_EXPR, type, diff, - fold_convert_loc (loc, type, esz)); - - } + tree tem = fold_addr_of_array_ref_difference (loc, type, + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0)); + if (tem) + return tem; } if (FLOAT_TYPE_P (type) @@ -10292,12 +10677,15 @@ fold_binary_loc (location_t loc, && (tem = distribute_real_division (loc, code, type, arg0, arg1))) return tem; - /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the - same or one. Make sure type is not saturating. - fold_plusminus_mult_expr will re-associate. */ + /* 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); @@ -10598,9 +10986,9 @@ fold_binary_loc (location_t loc, } } - /* Optimize x*x as pow(x,2.0), which is expanded as x*x. */ + /* Canonicalize x*x as pow(x,2.0), which is expanded as x*x. */ if (!in_gimple_form - && optimize_function_for_speed_p (cfun) + && optimize && operand_equal_p (arg0, arg1, 0)) { tree powfn = mathfn_built_in (type, BUILT_IN_POW); @@ -10647,66 +11035,50 @@ fold_binary_loc (location_t loc, && TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) { - unsigned HOST_WIDE_INT hi1, lo1, hi2, lo2, hi3, lo3, mlo, mhi; + double_int c1, c2, c3, msk; int width = TYPE_PRECISION (type), w; - hi1 = TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)); - lo1 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)); - hi2 = TREE_INT_CST_HIGH (arg1); - lo2 = TREE_INT_CST_LOW (arg1); + c1 = tree_to_double_int (TREE_OPERAND (arg0, 1)); + c2 = tree_to_double_int (arg1); /* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2). */ - if ((hi1 & hi2) == hi1 && (lo1 & lo2) == lo1) + if (double_int_equal_p (double_int_and (c1, c2), c1)) return omit_one_operand_loc (loc, type, arg1, - TREE_OPERAND (arg0, 0)); + TREE_OPERAND (arg0, 0)); - if (width > HOST_BITS_PER_WIDE_INT) - { - mhi = (unsigned HOST_WIDE_INT) -1 - >> (2 * HOST_BITS_PER_WIDE_INT - width); - mlo = -1; - } - else - { - mhi = 0; - mlo = (unsigned HOST_WIDE_INT) -1 - >> (HOST_BITS_PER_WIDE_INT - width); - } + msk = double_int_mask (width); /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */ - if ((~(hi1 | hi2) & mhi) == 0 && (~(lo1 | lo2) & mlo) == 0) + if (double_int_zero_p (double_int_and_not (msk, + double_int_ior (c1, c2)))) return fold_build2_loc (loc, BIT_IOR_EXPR, type, - TREE_OPERAND (arg0, 0), arg1); + TREE_OPERAND (arg0, 0), 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. */ - hi1 &= mhi; - lo1 &= mlo; - hi2 &= mhi; - lo2 &= mlo; - hi3 = hi1 & ~hi2; - lo3 = lo1 & ~lo2; + c1 = double_int_and (c1, msk); + c2 = double_int_and (c2, msk); + c3 = double_int_and_not (c1, c2); for (w = BITS_PER_UNIT; w <= width && w <= HOST_BITS_PER_WIDE_INT; w <<= 1) { unsigned HOST_WIDE_INT mask = (unsigned HOST_WIDE_INT) -1 >> (HOST_BITS_PER_WIDE_INT - w); - if (((lo1 | lo2) & mask) == mask - && (lo1 & ~mask) == 0 && hi1 == 0) + if (((c1.low | c2.low) & mask) == mask + && (c1.low & ~mask) == 0 && c1.high == 0) { - hi3 = 0; - lo3 = mask; + c3 = uhwi_to_double_int (mask); break; } } - if (hi3 != hi1 || lo3 != lo1) + if (!double_int_equal_p (c3, c1)) return fold_build2_loc (loc, BIT_IOR_EXPR, type, - fold_build2_loc (loc, BIT_AND_EXPR, type, - TREE_OPERAND (arg0, 0), - build_int_cst_wide (type, - lo3, hi3)), - arg1); + fold_build2_loc (loc, BIT_AND_EXPR, type, + TREE_OPERAND (arg0, 0), + double_int_to_tree (type, + c3)), + arg1); } /* (X & Y) | Y is (X, Y). */ @@ -12502,13 +12874,13 @@ fold_binary_loc (location_t loc, if (TREE_CODE (arg0) == BIT_XOR_EXPR && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), - build_int_cst (TREE_TYPE (arg0), 0)); + build_zero_cst (TREE_TYPE (arg0))); /* Likewise (X ^ Y) == X becomes Y == 0. X has no side-effects. */ if (TREE_CODE (arg0) == BIT_XOR_EXPR && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1)) return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 1), - build_int_cst (TREE_TYPE (arg0), 0)); + build_zero_cst (TREE_TYPE (arg0))); /* (X ^ C1) op C2 can be rewritten as X op (C1 ^ C2). */ if (TREE_CODE (arg0) == BIT_XOR_EXPR @@ -12596,7 +12968,7 @@ fold_binary_loc (location_t loc, BIT_XOR_EXPR, itype, arg00, arg10), arg01), - build_int_cst (itype, 0)); + build_zero_cst (itype)); if (operand_equal_p (arg01, arg10, 0)) return fold_build2_loc (loc, code, type, @@ -12605,7 +12977,7 @@ fold_binary_loc (location_t loc, BIT_XOR_EXPR, itype, arg00, arg11), arg01), - build_int_cst (itype, 0)); + build_zero_cst (itype)); if (operand_equal_p (arg00, arg11, 0)) return fold_build2_loc (loc, code, type, @@ -12614,7 +12986,7 @@ fold_binary_loc (location_t loc, BIT_XOR_EXPR, itype, arg01, arg10), arg00), - build_int_cst (itype, 0)); + build_zero_cst (itype)); if (operand_equal_p (arg00, arg10, 0)) return fold_build2_loc (loc, code, type, @@ -12623,7 +12995,7 @@ fold_binary_loc (location_t loc, BIT_XOR_EXPR, itype, arg01, arg11), arg00), - build_int_cst (itype, 0)); + build_zero_cst (itype)); } if (TREE_CODE (arg0) == BIT_XOR_EXPR @@ -13103,10 +13475,22 @@ fold_binary_loc (location_t loc, TREE_OPERAND (arg1, 1)), build_int_cst (TREE_TYPE (arg0), 0)); + /* 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) && TYPE_UNSIGNED (TREE_TYPE (arg0)) && CONVERT_EXPR_P (arg1) && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR + && (TYPE_PRECISION (TREE_TYPE (arg1)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0)))) + && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0))) + || (TYPE_PRECISION (TREE_TYPE (arg1)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0))))) && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0))) { tem = build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, @@ -13200,8 +13584,7 @@ fold_binary_loc (location_t loc, return build_complex (type, arg0, arg1); if (TREE_CODE (arg0) == REALPART_EXPR && TREE_CODE (arg1) == IMAGPART_EXPR - && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 0))) - == TYPE_MAIN_VARIANT (type)) + && TREE_TYPE (TREE_OPERAND (arg0, 0)) == type && operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0)) return omit_one_operand_loc (loc, type, TREE_OPERAND (arg0, 0), @@ -13212,6 +13595,73 @@ fold_binary_loc (location_t loc, /* An ASSERT_EXPR should never be passed to fold_binary. */ gcc_unreachable (); + case VEC_PACK_TRUNC_EXPR: + case VEC_PACK_FIX_TRUNC_EXPR: + { + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + tree *elts, vals = NULL_TREE; + + gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts / 2 + && TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)) == nelts / 2); + if (TREE_CODE (arg0) != VECTOR_CST || TREE_CODE (arg1) != VECTOR_CST) + return NULL_TREE; + + elts = XALLOCAVEC (tree, nelts); + if (!vec_cst_ctor_to_array (arg0, elts) + || !vec_cst_ctor_to_array (arg1, elts + nelts / 2)) + return NULL_TREE; + + for (i = 0; i < nelts; i++) + { + elts[i] = fold_convert_const (code == VEC_PACK_TRUNC_EXPR + ? NOP_EXPR : FIX_TRUNC_EXPR, + TREE_TYPE (type), elts[i]); + if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i])) + return NULL_TREE; + } + + for (i = 0; i < nelts; i++) + vals = tree_cons (NULL_TREE, elts[nelts - i - 1], vals); + return build_vector (type, vals); + } + + case VEC_WIDEN_MULT_LO_EXPR: + case VEC_WIDEN_MULT_HI_EXPR: + { + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + tree *elts, vals = NULL_TREE; + + gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts * 2 + && TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)) == nelts * 2); + if (TREE_CODE (arg0) != VECTOR_CST || TREE_CODE (arg1) != VECTOR_CST) + return NULL_TREE; + + elts = XALLOCAVEC (tree, nelts * 4); + if (!vec_cst_ctor_to_array (arg0, elts) + || !vec_cst_ctor_to_array (arg1, elts + nelts * 2)) + return NULL_TREE; + + if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_WIDEN_MULT_LO_EXPR)) + elts += nelts; + + for (i = 0; i < nelts; i++) + { + elts[i] = fold_convert_const (NOP_EXPR, TREE_TYPE (type), elts[i]); + elts[i + nelts * 2] + = fold_convert_const (NOP_EXPR, TREE_TYPE (type), + elts[i + nelts * 2]); + if (elts[i] == NULL_TREE || elts[i + nelts * 2] == NULL_TREE) + return NULL_TREE; + elts[i] = const_binop (MULT_EXPR, elts[i], elts[i + nelts * 2]); + if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i])) + return NULL_TREE; + } + + for (i = 0; i < nelts; i++) + vals = tree_cons (NULL_TREE, elts[nelts - i - 1], vals); + return build_vector (type, vals); + } + default: return NULL_TREE; } /* switch (code) */ @@ -13553,7 +14003,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, case BIT_FIELD_REF: if ((TREE_CODE (arg0) == VECTOR_CST - || (TREE_CODE (arg0) == CONSTRUCTOR && TREE_CONSTANT (arg0))) + || TREE_CODE (arg0) == CONSTRUCTOR) && type == TREE_TYPE (TREE_TYPE (arg0))) { unsigned HOST_WIDE_INT width = tree_low_cst (arg1, 1); @@ -13565,24 +14015,17 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, && (idx = idx / width) < TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0))) { - tree elements = NULL_TREE; - if (TREE_CODE (arg0) == VECTOR_CST) - elements = TREE_VECTOR_CST_ELTS (arg0); - else { - unsigned HOST_WIDE_INT idx; - tree value; - - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (arg0), idx, value) - elements = tree_cons (NULL_TREE, value, elements); + tree elements = TREE_VECTOR_CST_ELTS (arg0); + while (idx-- > 0 && elements) + elements = TREE_CHAIN (elements); + if (elements) + return TREE_VALUE (elements); } - while (idx-- > 0 && elements) - elements = TREE_CHAIN (elements); - if (elements) - return TREE_VALUE (elements); - else - return build_zero_cst (type); + else if (idx < CONSTRUCTOR_NELTS (arg0)) + return CONSTRUCTOR_ELT (arg0, idx)->value; + return build_zero_cst (type); } } @@ -13605,6 +14048,55 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, return fold_fma (loc, type, arg0, arg1, arg2); + case VEC_PERM_EXPR: + if (TREE_CODE (arg2) == VECTOR_CST) + { + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + unsigned char *sel = XALLOCAVEC (unsigned char, nelts); + tree t; + bool need_mask_canon = false; + + gcc_assert (nelts == TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg2))); + for (i = 0, t = TREE_VECTOR_CST_ELTS (arg2); + i < nelts && t; i++, t = TREE_CHAIN (t)) + { + if (TREE_CODE (TREE_VALUE (t)) != INTEGER_CST) + return NULL_TREE; + + sel[i] = TREE_INT_CST_LOW (TREE_VALUE (t)) & (2 * nelts - 1); + if (TREE_INT_CST_HIGH (TREE_VALUE (t)) + || ((unsigned HOST_WIDE_INT) + TREE_INT_CST_LOW (TREE_VALUE (t)) != sel[i])) + need_mask_canon = true; + } + if (t) + return NULL_TREE; + for (; i < nelts; i++) + sel[i] = 0; + + if ((TREE_CODE (arg0) == VECTOR_CST + || TREE_CODE (arg0) == CONSTRUCTOR) + && (TREE_CODE (arg1) == VECTOR_CST + || TREE_CODE (arg1) == CONSTRUCTOR)) + { + t = fold_vec_perm (type, arg0, arg1, sel); + if (t != NULL_TREE) + return t; + } + + if (need_mask_canon && arg2 == op2) + { + tree list = NULL_TREE, eltype = TREE_TYPE (TREE_TYPE (arg2)); + for (i = 0; i < nelts; i++) + list = tree_cons (NULL_TREE, + build_int_cst (eltype, sel[nelts - i - 1]), + list); + t = build_vector (TREE_TYPE (arg2), list); + return build3_loc (loc, VEC_PERM_EXPR, type, op0, op1, t); + } + } + return NULL_TREE; + default: return NULL_TREE; } /* switch (code) */ @@ -13793,11 +14285,7 @@ fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, htab_t ht) union tree_node buf; int i, len; -recursive_label: - - gcc_assert ((sizeof (struct tree_exp) + 5 * sizeof (tree) - <= sizeof (struct tree_function_decl)) - && sizeof (struct tree_type) <= sizeof (struct tree_function_decl)); + recursive_label: if (expr == NULL) return; slot = (void **) htab_find_slot (ht, expr, INSERT); @@ -13835,7 +14323,8 @@ recursive_label: } } md5_process_bytes (expr, tree_size (expr), ctx); - fold_checksum_tree (TREE_TYPE (expr), ctx, ht); + 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