The function currently incorrectly assumes all the __builtin_clz* and .CLZ
calls have non-negative result. That is the case of the former which is UB
on zero and has [0, prec-1] return value otherwise, and is the case of the
single argument .CLZ as well (again, UB on zero), but for two argument
.CLZ is the case only if the second argument is also nonnegative (or if we
know the argument can't be zero, but let's do that just in the ranger IMHO).
The following patch does that.
2024-06-04 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/115337
* fold-const.cc (tree_call_nonnegative_warnv_p) <CASE_CFN_CLZ>:
If arg1 is non-NULL, RECURSE on it, otherwise return true.
* gcc.dg/bitint-106.c: New test.
CASE_CFN_FFS:
CASE_CFN_PARITY:
CASE_CFN_POPCOUNT:
- CASE_CFN_CLZ:
CASE_CFN_CLRSB:
case CFN_BUILT_IN_BSWAP16:
case CFN_BUILT_IN_BSWAP32:
/* Always true. */
return true;
+ CASE_CFN_CLZ:
+ if (arg1)
+ return RECURSE (arg1);
+ return true;
+
CASE_CFN_SQRT:
CASE_CFN_SQRT_FN:
/* sqrt(-0.0) is -0.0. */
--- /dev/null
+/* PR tree-optimization/115337 */
+/* { dg-do run { target bitint } } */
+/* { dg-options "-O2" } */
+
+#if __BITINT_MAXWIDTH__ >= 129
+#define N 128
+#else
+#define N 63
+#endif
+
+_BitInt (N) g;
+int c;
+
+void
+foo (unsigned _BitInt (N + 1) z, _BitInt (N) *ret)
+{
+ c = __builtin_stdc_first_leading_one (z << N);
+ _BitInt (N) y = *(_BitInt (N) *) __builtin_memset (&g, c, 5);
+ *ret = y;
+}
+
+int
+main ()
+{
+ _BitInt (N) x;
+ foo (0, &x);
+ if (c || g || x)
+ __builtin_abort ();
+}