[gcc r17-2322] PR target/99668: Improved complex to vector RTL expansion.

Roger Sayle via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
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" } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.