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.

        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

Reply via email to