In decode_field_reference, when combining an inner BIT_AND_EXPR mask
with an incoming mask of wider precision (from an outer condition),
the inner mask was unconditionally zero-extended using UNSIGNED.
When the inner mask is of a signed type and its sign bit is set,
converting the masked value to the wider type sign-extends it, so tests
of the upper extension bits in the incoming mask are tests of the sign bit
of the inner expression. Hardcoding UNSIGNED zeroed out the upper bits of
the mask, which wiped out any extension bits from the incoming mask and
caused decode_field_reference to conclude that no sign-extension bits
were tested. This resulted in dropping the sign-bit check and miscompiling
the outer condition.
Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.
PR tree-optimization/128051
* gimple-fold.cc (decode_field_reference): Use TYPE_SIGN of mask
operand when extending and_mask to prec_in.
* gcc.dg/torture/pr128051.c: New testcase.
---
gcc/gimple-fold.cc | 3 +-
gcc/testsuite/gcc.dg/torture/pr128051.c | 44 +++++++++++++++++++++++++
2 files changed, 46 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.dg/torture/pr128051.c
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index bc5742c3b9b..e0197edece6 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -7988,7 +7988,8 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT
*pbitsize,
if (prec_in >= prec_op)
{
if (prec_in > prec_op)
- and_mask = wide_int::from (and_mask, prec_in, UNSIGNED);
+ and_mask = wide_int::from (and_mask, prec_in,
+ TYPE_SIGN (TREE_TYPE (res_ops[1])));
and_mask &= *pand_mask;
}
else
diff --git a/gcc/testsuite/gcc.dg/torture/pr128051.c
b/gcc/testsuite/gcc.dg/torture/pr128051.c
new file mode 100644
index 00000000000..7296410fa2e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr128051.c
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-require-effective-target int32plus } */
+
+int cnt;
+__attribute__((noipa)) void hit(void) { cnt++; }
+
+__attribute__((noipa)) void f(int x) {
+ if (((__INT64_TYPE__)(x & -4) & (__INT64_TYPE__)0xFFFFFFFF00000000ULL) == 0
&& (x & 1) == 1)
+ hit();
+}
+
+#if __SIZEOF_LONG__ >= 8
+__attribute__((noipa)) void f_long(int x) {
+ if (((long)(x & -4) & 0xFFFFFFFF00000000L) == 0 && (x & 1) == 1)
+ hit();
+}
+#endif
+
+int main(void) {
+ f(-5);
+ if (cnt != 0)
+ __builtin_abort();
+ f(5);
+ if (cnt != 1)
+ __builtin_abort();
+ f(-1);
+ if (cnt != 1)
+ __builtin_abort();
+ f(1);
+ if (cnt != 2)
+ __builtin_abort();
+
+#if __SIZEOF_LONG__ >= 8
+ cnt = 0;
+ f_long(-5);
+ if (cnt != 0)
+ __builtin_abort();
+ f_long(5);
+ if (cnt != 1)
+ __builtin_abort();
+#endif
+
+ return 0;
+}
base-commit: 0f7c27bb0d9c1a7346fc273615c0a103e1f6f8cf
prerequisite-patch-id: e52d299db98b0892f974152cd9fa5f6859fec5b7
prerequisite-patch-id: 39da6ec3264bae454fa504f127cd5b80a0662f04
prerequisite-patch-id: 6d6c263a964425334ad8c2edd4dd89dcbff44bfe
prerequisite-patch-id: 9a12a1706cbdff1edf8959682cd3cf9d900cd8f1
prerequisite-patch-id: dcb6febf1dbf6ea505f87a9c8c3572804a12819e
prerequisite-patch-id: b24057443c46d6979436cce479836178b19355de
prerequisite-patch-id: d61bf2c4249ecd3d9da5eeda002d332ed3a8b4fd
prerequisite-patch-id: 59cbeca60f782f48f945bc532c2235a50de6f0e5
prerequisite-patch-id: 8eddd3172e2007d0fc591124a56b372dfe83e683
prerequisite-patch-id: 862842dd3742066d039f66ffe9528bc490308c50
prerequisite-patch-id: e413d39d9af45f25483eaf229cf883c771444fbb
prerequisite-patch-id: 2faef186ad1d816bb104d89638bc4cec6d863a46
prerequisite-patch-id: b32cceb111f4f57798e4b1d58822281e7bbaf25e
prerequisite-patch-id: 404fd84b023dbe3994be05f26d6a86e83486d405
--
2.51.0