https://gcc.gnu.org/g:7a5da9ab53a8c4b6ffe03ef569b3ffe0ef096878

commit r16-4021-g7a5da9ab53a8c4b6ffe03ef569b3ffe0ef096878
Author: Pan Li <pan2...@intel.com>
Date:   Mon Sep 22 14:31:41 2025 +0800

    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 <pan2...@intel.com>

Diff:
---
 gcc/testsuite/gcc.target/i386/pr122021-0.c | 22 ++++++++++++++++++++++
 gcc/tree-ssa-math-opts.cc                  | 18 +++++++++++++++---
 2 files changed, 37 insertions(+), 3 deletions(-)

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 000000000000..de17734523cd
--- /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 344ffddd3859..80d10d26f678 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;
+           }
        }
     }

Reply via email to