https://gcc.gnu.org/g:badd64289a496c0fdb50f39fc2edeb4d124a8d0d

commit r16-6976-gbadd64289a496c0fdb50f39fc2edeb4d124a8d0d
Author: Robin Dapp <[email protected]>
Date:   Wed Jan 21 08:20:48 2026 +0100

    forwprop: More nop-conversion handling [PR123731].
    
    Since relaxing the constraints for permutes in r16-6671 for simplifying
    vector constructors there is an additional case to be handled as it
    interacts with r16-5561 (that allows nop conversions).
    
    In
      vector(8) short unsigned int _4;
      short int _5;
      vector(4) unsigned int _17;
    
      _3 = *a_14(D);
      _2 = {_3, { 0, 0, 0, 0 }};
      _4 = VEC_PERM_EXPR <{ 0, 0, 0, 0, 0, 0, 0, 0 }, _2, { 0, 9, 11, 3, 10, 2, 
9, 8 }>;
      _5 = BIT_FIELD_REF <_4, 16, 32>;
      d_16 = (unsigned int) _5;
      _17 = {d_16, d_16, d_16, d_16};
    
    we failed to consider that _5 is a signed type and directly converted to
    unsigned.
    
    With this patch we do
      _3 = *a_14(D);
      _5 = BIT_FIELD_REF <_3, 16, 48>;
      d_16 = (unsigned int) _5;
      _15 = VEC_PERM_EXPR <_3, _3, { 3, 3, 3, 3 }>;
      _1 = VIEW_CONVERT_EXPR<vector(4) short int>(_15);
      _21 = (vector(4) unsigned int) _1;
    
    where the two conversions can often be done in one instruction.
    
            PR tree-optimization/123731
    
    gcc/ChangeLog:
    
            * tree-ssa-forwprop.cc (simplify_vector_constructor): Handle nop
            conversion between during extraction.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/vect/pr123731.c: New test.

Diff:
---
 gcc/testsuite/gcc.dg/vect/pr123731.c | 28 ++++++++++++++++++++++++++++
 gcc/tree-ssa-forwprop.cc             | 19 ++++++++++++++++---
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/vect/pr123731.c 
b/gcc/testsuite/gcc.dg/vect/pr123731.c
new file mode 100644
index 000000000000..81fdb5d53bc5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr123731.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+
+typedef unsigned short A __attribute__ ((vector_size (4 * sizeof (short))));
+typedef short B __attribute__ ((vector_size (8 * sizeof (short))));
+typedef unsigned C __attribute__ ((vector_size (4 * sizeof (int))));
+unsigned long long c;
+
+__attribute__ ((noipa)) void
+foo (A *a)
+{
+  C b[9] = {};
+  unsigned d = __builtin_convertvector (
+  __builtin_shufflevector ((A) {}, *a, 0, 5, 7, 3, 6, 2, 5, 4), B)[2];
+  b[0] += (C) {d, d, d, d};
+  c += b[0][0];
+}
+
+int
+main ()
+{
+  A t = (A) {0, 0, 0, -6};
+  foo (&t);
+  if (sizeof (short) == 2
+      && sizeof (int) == 4
+      && __CHAR_BIT__ == 8
+      && c != -6U)
+    __builtin_abort ();
+}
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index bdc63a7a71bc..51de6308a091 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -4137,9 +4137,15 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
        return false;
       tree mask_type, perm_type, conv_src_type;
       perm_type = TREE_TYPE (orig[0]);
-      conv_src_type = (nelts == refnelts
-                      ? perm_type
-                      : build_vector_type (TREE_TYPE (perm_type), nelts));
+      /* Determine the element type for the conversion source.
+        As orig_elem_type keeps track of the original type, check
+        if we need to perform a sign swap after permuting.  */
+      tree conv_elem_type = TREE_TYPE (perm_type);
+      if (conv_code != ERROR_MARK
+         && orig_elem_type[0]
+         && tree_nop_conversion_p (orig_elem_type[0], conv_elem_type))
+       conv_elem_type = orig_elem_type[0];
+      conv_src_type = build_vector_type (conv_elem_type, nelts);
       if (conv_code != ERROR_MARK
          && !supportable_convert_operation (conv_code, type, conv_src_type,
                                             &conv_code))
@@ -4257,6 +4263,8 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
        = converted_orig1 ? build_zero_cst (perm_type) : orig[1];
       tree res = gimple_build (&stmts, VEC_PERM_EXPR, perm_type,
                               orig[0], orig1_for_perm, op2);
+      /* If we're building a smaller vector, extract the element
+        with the proper type.  */
       if (nelts != refnelts)
        res = gimple_build (&stmts, BIT_FIELD_REF,
                            conv_code != ERROR_MARK ? conv_src_type : type,
@@ -4264,6 +4272,11 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
                            TYPE_SIZE (conv_code != ERROR_MARK ? conv_src_type
                                                               : type),
                            bitsize_zero_node);
+      /* Otherwise, we can still have an intermediate sign change.  */
+      else if (conv_code != ERROR_MARK
+              && tree_nop_conversion_p (conv_src_type, perm_type))
+       res = gimple_build (&stmts, VIEW_CONVERT_EXPR, conv_src_type, res);
+      /* Finally, apply the conversion.  */
       if (conv_code != ERROR_MARK)
        res = gimple_build (&stmts, conv_code, type, res);
       else if (!useless_type_conversion_p (type, TREE_TYPE (res)))

Reply via email to