https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125709
Drea Pinski <pinskia at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |NEW
Summary|Possible missed |`a /(1<<b)` for signed
|optimization at O3 |types is not always
| |optimized to `a << b` when
| |is nonnegative
Ever confirmed|0 |1
Severity|normal |enhancement
Keywords| |missed-optimization
Last reconfirmed| |2026-06-10
--- Comment #1 from Drea Pinski <pinskia at gcc dot gnu.org> ---
Simplified:
```
int src(int v0_u8, int b) {
if (v0_u8<0||v0_u8>=31) __builtin_unreachable();
if (b<0) __builtin_unreachable();
int i0_u8 = 1 << v0_u8;
int i1_u8 = b / i0_u8;
return i1_u8;
}
```
There are 1 missed optimizations dealing with:
/* (A / (1 << B)) -> (A >> B).
Only for unsigned A. For signed A, this would not preserve rounding
toward zero.
For example: (-1 / ( 1 << B)) != -1 >> B.
Also handle widening conversions, like:
(A / (unsigned long long) (1U << B)) -> (A >> B)
or
(A / (unsigned long long) (1 << B)) -> (A >> B).
If the left shift is signed, it can be done only if the upper bits
of A starting from shift's type sign bit are zero, as
(unsigned long long) (1 << 31) is -2147483648ULL, not 2147483648ULL,
so it is valid only if A >> 31 is zero. */
(for div (trunc_div exact_div)
(simplify
(div (convert?@0 @3) (convert2? (lshift integer_onep@1 @2)))
(if ((TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (@0))
&& (!VECTOR_TYPE_P (type)
|| target_supports_op_p (type, RSHIFT_EXPR, optab_vector)
|| target_supports_op_p (type, RSHIFT_EXPR, optab_scalar))
&& (useless_type_conversion_p (type, TREE_TYPE (@1))
|| (element_precision (type) >= element_precision (TREE_TYPE (@1))
&& (TYPE_UNSIGNED (TREE_TYPE (@1))
|| (element_precision (type)
== element_precision (TREE_TYPE (@1)))
|| (INTEGRAL_TYPE_P (type)
&& (tree_nonzero_bits (@0)
& wi::mask (element_precision (TREE_TYPE (@1)) - 1,
true,
element_precision (type))) == 0)))))
(if (!VECTOR_TYPE_P (type)
&& useless_type_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1))
&& element_precision (TREE_TYPE (@3)) < element_precision (type))
(convert (rshift @3 @2))
(rshift @0 @2)))))
Either LLVM produces wrong code in one case or GCC's checks are too restrive.