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.

Reply via email to