The test is trying to shift by 129, but the underlying type is 128 bits.
This causes low_bits to wrap around to -1 and things go bad really
quick.

Attached is my proposed solution.

Andrew, do you have a preference on how to fix this?

gcc/ChangeLog:

        PR tree-optimization/97488
        * range-op.cc (operator_lshift::op1_range): Handle large right shifts.

gcc/testsuite/ChangeLog:

        * gcc.dg/pr97488.c: New test.
---
 gcc/range-op.cc                |  6 ++++--
 gcc/testsuite/gcc.dg/pr97488.c | 11 +++++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr97488.c

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 30d2a4d3987..13a0ee37feb 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -1608,8 +1608,10 @@ operator_lshift::op1_range (irange &r,
       // This would be [0x42, 0xFC] aka [01000010, 11111100].
 
       // Ideally we do this for each subrange, but just lump them all for now.
-      unsigned low_bits = TYPE_PRECISION (utype)
-                         - TREE_INT_CST_LOW (shift_amount);
+      unsigned saturated_shift_amount = TREE_INT_CST_LOW (shift_amount);
+      if (saturated_shift_amount > TYPE_PRECISION (utype))
+       saturated_shift_amount = TYPE_PRECISION (utype);
+      unsigned low_bits = TYPE_PRECISION (utype) - saturated_shift_amount;
       wide_int up_mask = wi::mask (low_bits, true, TYPE_PRECISION (utype));
       wide_int new_ub = wi::bit_or (up_mask, r.upper_bound ());
       wide_int new_lb = wi::set_bit (r.lower_bound (), low_bits);
diff --git a/gcc/testsuite/gcc.dg/pr97488.c b/gcc/testsuite/gcc.dg/pr97488.c
new file mode 100644
index 00000000000..96dc33cf258
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr97488.c
@@ -0,0 +1,11 @@
+// { dg-do compile }
+// { dg-options "-O1 -ftree-vrp" }
+
+__int128
+ef (__int128 ms)
+{
+  int dh = 129;
+  int *hj = &dh;
+
+  return ms << *hj ? ms : 0;
+}
-- 
2.25.4

Reply via email to