This has been pending in my queue for a while. Just keeps getting
pushed down.
As the PR notes, I added a patch a while back that could reassociate an
xor operation out of certain sequences which in turn would allow the
sequence to be recognized as rotate+xor.
That patch did not handle 128 bit integers as I used the HOST_WIDE_INT
interfaces. Similarly it didn't handle BitInt.
This patch changes it to use the wi:: interfaces which fix the code
generation issue on aarch64 with int128 and allow the sequence to safely
fire for BitInt. The recommendations for adjustment were Jakub's.
Bootstrapped and regression tested on x86, aarch64 and riscv. Crosses
also tested without regressions, though I don't think they provide
meaningfully more coverage for int128 and BitInt.
OK for the trunk?
Jeff
diff --git a/gcc/match.pd b/gcc/match.pd
index 54cad1cd2bc..d0ea9153c6b 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -13319,8 +13319,7 @@ and,
(if (type_has_mode_precision_p (type)
&& tree_fits_uhwi_p (@1)
&& tree_fits_uhwi_p (@3)
- && tree_fits_uhwi_p (@4)
- && ((~((HOST_WIDE_INT_1U << tree_to_uhwi (@1)) - 1)) & tree_to_uhwi (@4)) == 0
+ && (wi::mask (tree_to_uhwi (@1), true, TYPE_PRECISION (type)) & wi::to_wide (@4)) == 0
&& (tree_to_uhwi (@1) + tree_to_uhwi (@3)) == TYPE_PRECISION (type)
&& TYPE_UNSIGNED (type)
&& @0 == @2)
@@ -13333,9 +13332,8 @@ and,
(rshift @3 INTEGER_CST@4))
(if (type_has_mode_precision_p (type)
&& tree_fits_uhwi_p (@1)
- && tree_fits_uhwi_p (@2)
&& tree_fits_uhwi_p (@4)
- && (((((HOST_WIDE_INT_1U << tree_to_uhwi (@1)) - 1)) & tree_to_uhwi (@2)) == 0)
+ && ((wi::mask (tree_to_uhwi (@1), false, TYPE_PRECISION (type)) & wi::to_wide (@2)) == 0)
&& (tree_to_uhwi (@1) + tree_to_uhwi (@4)) == TYPE_PRECISION (type)
&& TYPE_UNSIGNED (type)
&& @0 == @3)
diff --git a/gcc/testsuite/gcc.dg/torture/pr126462.c b/gcc/testsuite/gcc.dg/torture/pr126462.c
new file mode 100644
index 00000000000..d32ba6f04ed
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr126462.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target int128 } } */
+
+typedef unsigned __int128 u128;
+
+__attribute__((noipa)) u128
+f (u128 x)
+{
+ return ((x << 64) ^ (u128) 1) | (x >> 64);
+}
+
+__attribute__((noipa)) u128
+g (u128 x)
+{
+ return ((x << 96) ^ ((u128) 1 << 32)) | (x >> 32);
+}
+
+int
+main (void)
+{
+ u128 x = (u128) 1 << 64;
+ if (f (x) != 1)
+ __builtin_abort ();
+ if (g (x) != ((u128) 1 << 32))
+ __builtin_abort ();
+ return 0;
+}