Ping!

Please review.

Thanks & Regards,
Kishan
On 26/06/25 1:26 pm, Kishan Parmar wrote:
> Hi All,
>
> The following patch has been bootstrapped and regtested on powerpc64le-linux.
>
> While building GCC with --with-build-config=bootstrap-ubsan on
> powerpc64le-unknown-linux-gnu, multiple UBSAN runtime errors were
> encountered in rs6000.cc and rs6000.md due to undefined behavior
> involving left shifts on negative values and shift exponents equal to
> or exceeding the type width.
>
> The issue was in bit pattern recognition code
> (in can_be_rotated_to_negative_lis and can_be_built_by_li_and_rldic),
> where signed values were shifted without handling negative inputs or
> guarding against shift counts equal to the type width, causing UB.
> The fix ensures shifts and rotations are done unsigned HOST_WIDE_INT,
> and casting back only where needed (like for arithmetic right shifts)
> with proper guards to prevent shift-by-64.
>
> 2025-06-26  Kishan Parmar  <kis...@linux.ibm.com>
>
> gcc:
>       PR target/118890
>       * config/rs6000/rs6000.cc (can_be_rotated_to_negative_lis):
>       Avoid left shift of negative value and guard shift count.
>       (can_be_built_by_li_and_rldic): Likewise.
>       (rs6000_emit_set_long_const): Likewise.
>       * config/rs6000/rs6000.md : Avoid signed overflow.
> ---
>  gcc/config/rs6000/rs6000.cc | 24 ++++++++++++++----------
>  gcc/config/rs6000/rs6000.md |  4 +++-
>  2 files changed, 17 insertions(+), 11 deletions(-)
>
> diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
> index 7ee26e52b13..e7e30fa95ba 100644
> --- a/gcc/config/rs6000/rs6000.cc
> +++ b/gcc/config/rs6000/rs6000.cc
> @@ -10309,15 +10309,18 @@ can_be_rotated_to_negative_lis (HOST_WIDE_INT c, 
> int *rot)
>  
>    /* case b. xx0..01..1xx: some of 15 x's (and some of 16 0's) are
>       rotated over the highest bit.  */
> -  int pos_one = clz_hwi ((c << 16) >> 16);
> -  middle_zeros = ctz_hwi (c >> (HOST_BITS_PER_WIDE_INT - pos_one));
> -  int middle_ones = clz_hwi (~(c << pos_one));
> -  if (middle_zeros >= 16 && middle_ones >= 33)
> +  unsigned HOST_WIDE_INT uc = (unsigned HOST_WIDE_INT)c;
> +  int pos_one = clz_hwi ((HOST_WIDE_INT)(uc << 16) >> 16);
> +  if (pos_one != 0)
>      {
> -      *rot = pos_one;
> -      return true;
> +      middle_zeros = ctz_hwi (c >> (HOST_BITS_PER_WIDE_INT - pos_one));
> +      int middle_ones = clz_hwi (~(uc << pos_one));
> +      if (middle_zeros >= 16 && middle_ones >= 33)
> +     {
> +       *rot = pos_one;
> +       return true;
> +     }
>      }
> -
>    return false;
>  }
>  
> @@ -10434,7 +10437,7 @@ can_be_built_by_li_and_rldic (HOST_WIDE_INT c, int 
> *shift, HOST_WIDE_INT *mask)
>    if (lz >= HOST_BITS_PER_WIDE_INT)
>      return false;
>  
> -  int middle_ones = clz_hwi (~(c << lz));
> +  int middle_ones = clz_hwi (~(((unsigned HOST_WIDE_INT)c) << lz));
>    if (tz + lz + middle_ones >= ones
>        && (tz - lz) < HOST_BITS_PER_WIDE_INT
>        && tz < HOST_BITS_PER_WIDE_INT)
> @@ -10468,7 +10471,7 @@ can_be_built_by_li_and_rldic (HOST_WIDE_INT c, int 
> *shift, HOST_WIDE_INT *mask)
>    if (!IN_RANGE (pos_first_1, 1, HOST_BITS_PER_WIDE_INT-1))
>      return false;
>  
> -  middle_ones = clz_hwi (~c << pos_first_1);
> +  middle_ones = clz_hwi ((~(unsigned HOST_WIDE_INT)c) << pos_first_1);
>    middle_zeros = ctz_hwi (c >> (HOST_BITS_PER_WIDE_INT - pos_first_1));
>    if (pos_first_1 < HOST_BITS_PER_WIDE_INT
>        && middle_ones + middle_zeros < HOST_BITS_PER_WIDE_INT
> @@ -10570,7 +10573,8 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT 
> c, int *num_insns)
>      {
>        /* li/lis; rldicX */
>        unsigned HOST_WIDE_INT imm = (c | ~mask);
> -      imm = (imm >> shift) | (imm << (HOST_BITS_PER_WIDE_INT - shift));
> +      if (shift != 0)
> +     imm = (imm >> shift) | (imm << (HOST_BITS_PER_WIDE_INT - shift));
>  
>        count_or_emit_insn (temp, GEN_INT (imm));
>        if (shift != 0)
> diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
> index 9c718ca2a22..8fc079a4297 100644
> --- a/gcc/config/rs6000/rs6000.md
> +++ b/gcc/config/rs6000/rs6000.md
> @@ -1971,7 +1971,9 @@
>  {
>    HOST_WIDE_INT val = INTVAL (operands[2]);
>    HOST_WIDE_INT low = sext_hwi (val, 16);
> -  HOST_WIDE_INT rest = trunc_int_for_mode (val - low, <MODE>mode);
> +  /* Avoid signed overflow by computing difference in unsigned domain.  */
> +  unsigned HOST_WIDE_INT urest = (unsigned HOST_WIDE_INT)val - (unsigned 
> HOST_WIDE_INT)low;
> +  HOST_WIDE_INT rest = trunc_int_for_mode (urest, <MODE>mode);
>  
>    operands[4] = GEN_INT (low);
>    if (<MODE>mode == SImode || satisfies_constraint_L (GEN_INT (rest)))

Reply via email to