aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2015-12-22 21:47:58 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2015-12-22 21:47:58 +0100
commitd6dd2c8e29213be6d5f95106bcb9b2cb7cbabb48 (patch)
tree2db18c0a05eec9cf42467509904fc197af7af259
parentb5c4bc31baa52fc4ef51a89dcf97413f34c86d70 (diff)
downloadgcc-d6dd2c8e29213be6d5f95106bcb9b2cb7cbabb48.zip
gcc-d6dd2c8e29213be6d5f95106bcb9b2cb7cbabb48.tar.gz
gcc-d6dd2c8e29213be6d5f95106bcb9b2cb7cbabb48.tar.bz2
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) <case EQ_EXPR, NE_EXPR>: 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
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/fold-const.c123
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-67376.C17
4 files changed, 112 insertions, 44 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 473119a..73ab7d4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2015-12-22 Jakub Jelinek <jakub@redhat.com>
+
+ 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) <case EQ_EXPR, NE_EXPR>: 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 <rth@redhat.com>
PR ipa/67811
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5ad5112..4fd0979 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 3c2e2ac..b0eb469 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2015-12-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/67376
+ * g++.dg/cpp0x/constexpr-67376.C: New test.
+
2015-12-22 Richard Henderson <rth@redhat.com>
* 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 0000000..41043c8
--- /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, "");