From: Pan Li Date: Mon, 22 Sep 2025 06:31:41 +0000 (+0800) Subject: Widen-Mul: Fix mis-compile for build_and_insert_cast refinement [PR122021] X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7a5da9ab53a8c4b6ffe03ef569b3ffe0ef096878;p=thirdparty%2Fgcc.git Widen-Mul: Fix mis-compile for build_and_insert_cast refinement [PR122021] 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. 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 --- 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 +#include + +__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; + } } }