This fixes the wrong-code regression in PR ipa/128092:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128092
The IPA bit lattice can mark bits above the operand precision as
unknown. Passing those bits to value_mask_to_min_max can make it
mistake them for a varying sign bit and misfold MAX_EXPR. Extend the
value and mask to the operation's precision and signedness before
calling the unary or binary bit folder.
The new torture test covers the reduced reproducer, including LTO.
Bootstrapped and regression-tested on x86_64-pc-linux-gnu with the
default languages and --disable-multilib, with no new test failures.
The libgomp tests were rerun after fixing a local Tcl module-path
issue.
OK for trunk? If approved, please commit it on my behalf.
Assisted-by: OpenAI Codex
gcc/ChangeLog:
PR ipa/128092
* ipa-cp.cc (ipcp_bits_lattice::meet_with): Extend the source value
and mask to the operation type before folding.
gcc/testsuite/ChangeLog:
PR ipa/128092
* g++.dg/torture/pr128092.C: New test.
---
diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index cecc8d17f..daea1da62 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1050,6 +1050,9 @@ ipcp_bits_lattice::meet_with (ipcp_bits_lattice&
other, unsigned precision,
return false;
widest_int adjusted_value, adjusted_mask;
+ /* The lattice may mark bits above PRECISION as unknown. */
+ widest_int value = wi::ext (other.get_value (), precision, sgn);
+ widest_int mask = wi::ext (other.get_mask (), precision, sgn);
if (TREE_CODE_CLASS (code) == tcc_binary)
{
@@ -1058,7 +1061,7 @@ ipcp_bits_lattice::meet_with (ipcp_bits_lattice&
other, unsigned precision,
get_value_and_mask (operand, &o_value, &o_mask);
bit_value_binop (code, sgn, precision, &adjusted_value, &adjusted_mask,
- sgn, precision, other.get_value (), other.get_mask (),
+ sgn, precision, value, mask,
TYPE_SIGN (type), TYPE_PRECISION (type), o_value,
o_mask);
if (wi::sext (adjusted_mask, precision) == -1)
@@ -1068,8 +1071,7 @@ ipcp_bits_lattice::meet_with (ipcp_bits_lattice&
other, unsigned precision,
else if (TREE_CODE_CLASS (code) == tcc_unary)
{
bit_value_unop (code, sgn, precision, &adjusted_value,
- &adjusted_mask, sgn, precision, other.get_value (),
- other.get_mask ());
+ &adjusted_mask, sgn, precision, value, mask);
if (wi::sext (adjusted_mask, precision) == -1)
return set_to_bottom ();
diff --git a/gcc/testsuite/g++.dg/torture/pr128092.C
b/gcc/testsuite/g++.dg/torture/pr128092.C
new file mode 100644
index 000000000..152026430
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr128092.C
@@ -0,0 +1,20 @@
+/* { dg-do run { target c++11 } } */
+
+[[gnu::noinline]] static unsigned
+f (unsigned x)
+{
+ return x;
+}
+
+[[gnu::noinline]] static unsigned
+g (int x)
+{
+ return f (x > 0 ? x : 0);
+}
+
+int
+main ()
+{
+ if (g (1) + g (0) != 1)
+ __builtin_abort ();
+}