On Mon, Sep 22, 2025 at 9:57 AM <[email protected]> wrote: > > From: Pan Li <[email protected]> > > The previous refinement in build_and_insert_cast will convert 2 > cast into one, aka: > > uint16_t _3; > > From: > int16_t _4 = (uint16_t)_3; // no-extend > int32_t _5 = (int32_t)_4 // sign-extend 16 => 32 > > To: > int32_t _5 = (int32_t)_3; // zero-extend 16 => 32 > > That will have a problem for sign-extend, the highest bits may be all 1s > but will be loss after convert to zero-extend. Thus, there will be more > cases if the convert has different types. Case 1 as above and Case 2, > 3, and 4 as following. > > Case 2: > int16_t _3; > > From: > uint32_t _4 = (uint32_t)_3; // zero-extend 16 => 32 > uint64_t _5 = (uint64_t)_4; // zero-extend 32 => 64 > > To: > uint64_t _5 = (uint32_t)_3; // zero-extend 16 => 64 > > Case 3: > uint8_t _3; > > From: > uint16_t _4 = (uint16_t)_3; // zero-extend 8 => 16 > int32_t _5 = (int32_t)_4; // zero-extend 16 => 32 > > To: > int32_t _5 = (int32_t)_3; // zero-extend 8 => 32 > > Case 4: > int8_t _3; > > From: > int16_t _4 = (int16_t)_3; // sign-extend 8 => 16 > uint32_t _5 = (uint32_t)_4; // zero-extend 16 => 32 > To: > uint32_t _5 = (uint32_t)_3; // zero-extend 8 => 32 > > Then, we can see, there will be mis-compile if and only if there is > a cast from small to big size with sign extend. Thus, restrict the > check and stop prop if there is sign extend cast. > > The below test suites are passed for this patch: > 1. The rv64gcv fully regression tests. > 2. The x86 bootstrap tests. > 3. The x86 fully regression tests.
OK. Thanks, Richard. > PR middle-end/122021 > > gcc/ChangeLog: > > * tree-ssa-math-opts.cc (build_and_insert_cast): Add sign-extend > check before prop. > > gcc/testsuite/ChangeLog: > > * gcc.target/i386/pr122021-0.c: New test. > > Signed-off-by: Pan Li <[email protected]> > --- > gcc/testsuite/gcc.target/i386/pr122021-0.c | 22 ++++++++++++++++++++++ > gcc/tree-ssa-math-opts.cc | 18 +++++++++++++++--- > 2 files changed, 37 insertions(+), 3 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/i386/pr122021-0.c > > diff --git a/gcc/testsuite/gcc.target/i386/pr122021-0.c > b/gcc/testsuite/gcc.target/i386/pr122021-0.c > new file mode 100644 > index 00000000000..de17734523c > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr122021-0.c > @@ -0,0 +1,22 @@ > +/* { dg-do run } */ > +/* { dg-options "-O2 -m32" } */ > + > +#include <stddef.h> > +#include <stdint.h> > + > +__attribute__ ((noipa)) static void > +vp9_build_inter_predictor (int a) > +{ > + int16_t row = a * 2; > + int32_t row_w = (int)((int64_t)row * 16384 >> 14); > + > + if (row_w != -544) > + __builtin_abort (); > +} > + > +int > +main () > +{ > + vp9_build_inter_predictor (-272); > + return 0; > +} > diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc > index 344ffddd385..80d10d26f67 100644 > --- a/gcc/tree-ssa-math-opts.cc > +++ b/gcc/tree-ssa-math-opts.cc > @@ -1642,12 +1642,24 @@ build_and_insert_cast (gimple_stmt_iterator *gsi, > location_t loc, > && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def))) > { > tree cast_rhs = gimple_assign_rhs1 (def); > - unsigned rhs_prec = TYPE_PRECISION (TREE_TYPE (cast_rhs)); > + tree cast_rhs_type = TREE_TYPE (cast_rhs); > + tree val_type = TREE_TYPE (val); > + > + bool unsigned_p = TYPE_UNSIGNED (type); > + bool unsigned_rhs_p = TYPE_UNSIGNED (cast_rhs_type); > + bool unsigned_val_p = TYPE_UNSIGNED (val_type); > + > + unsigned rhs_prec = TYPE_PRECISION (cast_rhs_type); > unsigned type_prec = TYPE_PRECISION (type); > - unsigned val_prec = TYPE_PRECISION (TREE_TYPE (val)); > + unsigned val_prec = TYPE_PRECISION (val_type); > > if (type_prec >= rhs_prec && val_prec >= rhs_prec) > - rhs = cast_rhs; > + { > + /* Aka any sign extend from small to big size */ > + if (!((val_prec > rhs_prec && !unsigned_val_p && > !unsigned_rhs_p) > + || (type_prec > val_prec && !unsigned_p && > !unsigned_val_p))) > + rhs = rhs; > + } > } > } > > -- > 2.43.0 >
