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

commit r17-2322-gec31d8cb81aa2f9b74c3b91fb87080b9c86cea23
Author: Roger Sayle <[email protected]>
Date:   Fri Jul 10 22:59:24 2026 +0100

    PR target/99668: Improved complex to vector RTL expansion.
    
    This patch improves the RTL expansion of casts (VIEW_CONVERT_EXPR)
    from complex numbers to two-component vectors with the same inner
    type.  Currently, expand spills the complex number to memory to
    perform this conversion.  With the patch below we now convert the
    V_C_E into the equivalent of (v2x){__real__ z,__imag__ z}, using
    the backend's vec_init_optab.
    
    The motivating example from the Bugzilla PR is:
    
    typedef double v2df __attribute__((vector_size(16)));
    v2df foo (_Complex double x)
    {
      return *(v2df *)&x;
    }
    
    Currently, with -O2 GCC implements this by spilling to memory:
    
    foo:    movsd   %xmm0, -24(%rsp)
            movsd   %xmm1, -16(%rsp)
            movupd  -24(%rsp), %xmm0
            ret
    
    with this enhancement to RTL expansion, we now generate:
    
    foo:    unpcklpd        %xmm1, %xmm0
            ret
    
    The improvement with -m32 -msse2 -O2 is even more pronounced.
    
    From:   subl    $28, %esp
            movsd   32(%esp), %xmm1
            movsd   40(%esp), %xmm2
            movsd   %xmm1, (%esp)
            movsd   %xmm2, 8(%esp)
            movupd  (%esp), %xmm0
            addl    $28, %esp
            ret
    
    To:     movq    4(%esp), %xmm0
            movhpd  12(%esp), %xmm0
            ret
    
    2026-07-10  Roger Sayle  <[email protected]>
                Richard Biener  <[email protected]>
    
    gcc/ChangeLog
            PR target/99668
            * expr.cc (try_expand_complex_as_vector): Try to use vec_init_optab
            to convert a complex number to a two-component vector with the same
            inner type.
            (expand_expr_real_1) <case VIEW_CONVERT_EXPR>: Check whether the
            above function can be used to implement this VIEW_CONVERT_EXPR.
    
    gcc/testsuite/ChangeLog
            PR target/99668
            * gcc.target/i386/pr99668.c: New test case.

Diff:
---
 gcc/expr.cc                             | 45 +++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr99668.c | 12 +++++++++
 2 files changed, 57 insertions(+)

diff --git a/gcc/expr.cc b/gcc/expr.cc
index f42aab21272f..9933286df849 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -11382,6 +11382,45 @@ expand_expr_real_gassign (gassign *g, rtx target, 
machine_mode tmode,
   return r;
 }
 
+/* A subroutine of expand_expr_real_1.  Attempt to VIEW_CONVERT_EXPR
+   the complex expression OP0 to the vector mode MODE.  Store the
+   result at TARGET if possible (if TARGET is nonzero).  Returns
+   NULL_RTX on failure.  */
+static rtx
+try_expand_complex_as_vector (machine_mode mode, rtx op0, rtx target)
+{
+  if (COMPLEX_MODE_P (GET_MODE (op0))
+      && VECTOR_MODE_P (mode)
+      && known_eq (GET_MODE_NUNITS (mode), 2)
+      && GET_MODE_INNER (mode) == GET_MODE_INNER (GET_MODE (op0)))
+    {
+      enum insn_code icode = convert_optab_handler (vec_init_optab, mode,
+                                                   GET_MODE_INNER (mode));
+      if (icode != CODE_FOR_nothing)
+       {
+         if (!target || !REG_P (target))
+           target = gen_reg_rtx (mode);
+         rtx rpart = read_complex_part (op0, false);
+         rtx ipart = read_complex_part (op0, true);
+         if (!REG_P (rpart) && !CONSTANT_P (rpart))
+           rpart = force_reg (GET_MODE_INNER (mode), rpart);
+         if (!REG_P (ipart) && !CONSTANT_P (ipart))
+           ipart = force_reg (GET_MODE_INNER (mode), ipart);
+         rtvec vec = rtvec_alloc (2);
+         RTVEC_ELT (vec, 0) = rpart;
+         RTVEC_ELT (vec, 1) = ipart;
+         rtx par = gen_rtx_PARALLEL (mode, vec);
+         rtx_insn *insn = GEN_FCN (icode) (target, par);
+         if (insn)
+           {
+             emit_insn (insn);
+             return target;
+           }
+       }
+    }
+  return NULL_RTX;
+}
+
 rtx
 expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
                    enum expand_modifier modifier, rtx *alt_rtl,
@@ -12798,6 +12837,12 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
        return extract_bit_field (op0, TYPE_PRECISION (type), 0,
                                  TYPE_UNSIGNED (type), NULL_RTX,
                                  mode, mode, false, NULL);
+      /* If source is a complex number and destination is a
+        two-component vector with same inner type, try to use
+        vector initialization.  */
+      else if ((temp = try_expand_complex_as_vector (mode, op0, target))
+              != NULL_RTX)
+       return temp;
       /* As a last resort, spill op0 to memory, and reload it in a
         different mode.  */
       else if (!MEM_P (op0))
diff --git a/gcc/testsuite/gcc.target/i386/pr99668.c 
b/gcc/testsuite/gcc.target/i386/pr99668.c
new file mode 100644
index 000000000000..90bac6950831
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr99668.c
@@ -0,0 +1,12 @@
+/* PR target/99668 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+typedef double v2df __attribute__((vector_size(16)));
+v2df foo (_Complex double x)
+{
+  return *(v2df *)&x;
+}
+
+/* { dg-final { scan-assembler-not "\\tmovsd" } } */
+/* { dg-final { scan-assembler-not "movupd" } } */

Reply via email to