From: Jakub Jelinek Date: Tue, 22 Dec 2015 20:47:58 +0000 (+0100) Subject: re PR c++/67376 (Comparison with pointer to past-the-end of array fails inside consta... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d6dd2c8e29213be6d5f95106bcb9b2cb7cbabb48;p=gcc.git re PR c++/67376 (Comparison with pointer to past-the-end of array fails inside constant expression) PR c++/67376 * fold-const.c (size_low_cst): Removed. (fold_comparison): For POINTER_PLUS_EXPR where base is ADDR_EXPR call get_inner_reference and handle INDIRECT_REF base of it. Use offset_int for computation of the bitpos. (fold_binary_loc) : Formatting fixes for X +- Y CMP X and C - X CMP X folding. Add X CMP X +- Y and X CMP C - X folding. * g++.dg/cpp0x/constexpr-67376.C: New test. From-SVN: r231909 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 473119a629f..73ab7d40818 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2015-12-22 Jakub Jelinek + + PR c++/67376 + * fold-const.c (size_low_cst): Removed. + (fold_comparison): For POINTER_PLUS_EXPR where base is ADDR_EXPR + call get_inner_reference and handle INDIRECT_REF base of it. Use + offset_int for computation of the bitpos. + (fold_binary_loc) : Formatting + fixes for X +- Y CMP X and C - X CMP X folding. Add X CMP X +- Y + and X CMP C - X folding. + 2015-12-22 Richard Henderson PR ipa/67811 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 5ad51129922..4fd09795e6d 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -8294,20 +8294,6 @@ pointer_may_wrap_p (tree base, tree offset, HOST_WIDE_INT bitpos) return total.to_uhwi () > (unsigned HOST_WIDE_INT) size; } -/* Return the HOST_WIDE_INT least significant bits of T, a sizetype - kind INTEGER_CST. This makes sure to properly sign-extend the - constant. */ - -static HOST_WIDE_INT -size_low_cst (const_tree t) -{ - HOST_WIDE_INT w = TREE_INT_CST_ELT (t, 0); - int prec = TYPE_PRECISION (TREE_TYPE (t)); - if (prec < HOST_BITS_PER_WIDE_INT) - return sext_hwi (w, prec); - return w; -} - /* 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 @@ -8436,18 +8422,30 @@ fold_comparison (location_t loc, enum tree_code code, tree type, STRIP_SIGN_NOPS (base0); if (TREE_CODE (base0) == ADDR_EXPR) { - base0 = TREE_OPERAND (base0, 0); - indirect_base0 = true; + base0 + = get_inner_reference (TREE_OPERAND (base0, 0), + &bitsize, &bitpos0, &offset0, &mode, + &unsignedp, &reversep, &volatilep, + false); + if (TREE_CODE (base0) == INDIRECT_REF) + base0 = TREE_OPERAND (base0, 0); + else + indirect_base0 = true; } - offset0 = TREE_OPERAND (arg0, 1); - if (tree_fits_shwi_p (offset0)) + if (offset0 == NULL_TREE || integer_zerop (offset0)) + offset0 = TREE_OPERAND (arg0, 1); + else + offset0 = size_binop (PLUS_EXPR, offset0, + TREE_OPERAND (arg0, 1)); + if (TREE_CODE (offset0) == INTEGER_CST) { - 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) + offset_int tem = wi::sext (wi::to_offset (offset0), + TYPE_PRECISION (sizetype)); + tem = wi::lshift (tem, LOG2_BITS_PER_UNIT); + tem += bitpos0; + if (wi::fits_shwi_p (tem)) { - bitpos0 = off * BITS_PER_UNIT; + bitpos0 = tem.to_shwi (); offset0 = NULL_TREE; } } @@ -8471,18 +8469,30 @@ fold_comparison (location_t loc, enum tree_code code, tree type, STRIP_SIGN_NOPS (base1); if (TREE_CODE (base1) == ADDR_EXPR) { - base1 = TREE_OPERAND (base1, 0); - indirect_base1 = true; + base1 + = get_inner_reference (TREE_OPERAND (base1, 0), + &bitsize, &bitpos1, &offset1, &mode, + &unsignedp, &reversep, &volatilep, + false); + if (TREE_CODE (base1) == INDIRECT_REF) + base1 = TREE_OPERAND (base1, 0); + else + indirect_base1 = true; } - offset1 = TREE_OPERAND (arg1, 1); - if (tree_fits_shwi_p (offset1)) + if (offset1 == NULL_TREE || integer_zerop (offset1)) + offset1 = TREE_OPERAND (arg1, 1); + else + offset1 = size_binop (PLUS_EXPR, offset1, + TREE_OPERAND (arg1, 1)); + if (TREE_CODE (offset1) == INTEGER_CST) { - 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) + offset_int tem = wi::sext (wi::to_offset (offset1), + TYPE_PRECISION (sizetype)); + tem = wi::lshift (tem, LOG2_BITS_PER_UNIT); + tem += bitpos1; + if (wi::fits_shwi_p (tem)) { - bitpos1 = off * BITS_PER_UNIT; + bitpos1 = tem.to_shwi (); offset1 = NULL_TREE; } } @@ -10575,12 +10585,27 @@ fold_binary_loc (location_t loc, || POINTER_TYPE_P (TREE_TYPE (arg0)))) { tree val = TREE_OPERAND (arg0, 1); - return omit_two_operands_loc (loc, type, - fold_build2_loc (loc, code, type, - val, - build_int_cst (TREE_TYPE (val), - 0)), - TREE_OPERAND (arg0, 0), arg1); + val = fold_build2_loc (loc, code, type, val, + build_int_cst (TREE_TYPE (val), 0)); + return omit_two_operands_loc (loc, type, val, + TREE_OPERAND (arg0, 0), arg1); + } + + /* Transform comparisons of the form X CMP X +- Y to Y CMP 0. */ + if ((TREE_CODE (arg1) == PLUS_EXPR + || TREE_CODE (arg1) == POINTER_PLUS_EXPR + || TREE_CODE (arg1) == MINUS_EXPR) + && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg1, + 0)), + arg0, 0) + && (INTEGRAL_TYPE_P (TREE_TYPE (arg1)) + || POINTER_TYPE_P (TREE_TYPE (arg1)))) + { + tree val = TREE_OPERAND (arg1, 1); + val = fold_build2_loc (loc, code, type, val, + build_int_cst (TREE_TYPE (val), 0)); + return omit_two_operands_loc (loc, type, val, + TREE_OPERAND (arg1, 0), arg0); } /* Transform comparisons of the form C - X CMP X if C % 2 == 1. */ @@ -10590,12 +10615,22 @@ fold_binary_loc (location_t loc, 1)), arg1, 0) && wi::extract_uhwi (TREE_OPERAND (arg0, 0), 0, 1) == 1) - { - return omit_two_operands_loc (loc, type, - code == NE_EXPR - ? boolean_true_node : boolean_false_node, - TREE_OPERAND (arg0, 1), arg1); - } + return omit_two_operands_loc (loc, type, + code == NE_EXPR + ? boolean_true_node : boolean_false_node, + TREE_OPERAND (arg0, 1), arg1); + + /* Transform comparisons of the form X CMP C - X if C % 2 == 1. */ + if (TREE_CODE (arg1) == MINUS_EXPR + && TREE_CODE (TREE_OPERAND (arg1, 0)) == INTEGER_CST + && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg1, + 1)), + arg0, 0) + && wi::extract_uhwi (TREE_OPERAND (arg1, 0), 0, 1) == 1) + return omit_two_operands_loc (loc, type, + code == NE_EXPR + ? boolean_true_node : boolean_false_node, + TREE_OPERAND (arg1, 1), 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3c2e2aca9e5..b0eb4691f13 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-12-22 Jakub Jelinek + + PR c++/67376 + * g++.dg/cpp0x/constexpr-67376.C: New test. + 2015-12-22 Richard Henderson * g++.dg/tm/noexcept-1.C: Update expected must_not_throw count. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-67376.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-67376.C new file mode 100644 index 00000000000..41043c8e54e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-67376.C @@ -0,0 +1,17 @@ +// PR c++/67376 +// { dg-do compile { target c++11 } } + +struct A { int e[2]; }; +constexpr A a { { 0, 1 } }; +static_assert (a.e + 1 != a.e, ""); +static_assert (a.e != a.e + 1, ""); +static_assert (a.e + 2 != a.e, ""); +static_assert (a.e != a.e + 2, ""); +static_assert (a.e + 1 > a.e, ""); +static_assert (a.e < a.e + 1, ""); +static_assert (a.e + 2 > a.e, ""); +static_assert (a.e < a.e + 2, ""); +static_assert (a.e + 1 >= a.e, ""); +static_assert (a.e <= a.e + 1, ""); +static_assert (a.e + 2 >= a.e, ""); +static_assert (a.e <= a.e + 2, "");