Hi Richard,
Thanks for the review. Here's a revised patch incorporating your feedback.
I'd considered arguing that none of the other callers of vec_init_optab in
the middle-end currently allow it to FAIL, but with the factorization into
a helper function (so that icode doesn’t have to be looked up twice), it's
trivially easy to handle it here (and perhaps update the other callers in
future).
This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
and make -k check, both with and without --target_board=unix{-m32}
with no new failures. Ok for mainline?
2026-07-07 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.
Thanks again,
Roger
--
> -----Original Message-----
> From: Richard Biener <[email protected]>
> Sent: 01 July 2026 08:25
> To: Roger Sayle <[email protected]>
> Cc: GCC Patches <[email protected]>
> Subject: Re: [PATCH] PR target/99668: Improved complex to vector RTL
> expansion.
>
> On Tue, Jun 30, 2026 at 11:42 PM Roger Sayle <[email protected]>
> wrote:
> >
> >
> > 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
> >
> >
> > This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
> > and make -k check, both with and without --target_board=unix{-m32}
> > with no new failures. Ok for mainline?
>
> I'll note the documentation of vec_init doesn't state the pattern is not
> allowed to
> FAIL, so I think you need to handle the expander failing.
>
> Also
>
> + if (!REG_P (rpart) && !CONSTANT_P (rpart))
> + rpart = force_reg (GET_MODE_INNER (mode), rpart);
> + if (!REG_P (ipart) && !CONSTANT_P (ipart))
>
> I think there's one extra space after part) and it would be nice to do the
> icode =
> convert_optab_handler assignment as part of the if () to not repeat it.
>
> Otherwise a good idea.
>
> Thanks,
> Richard.
>
> >
> >
> > 2026-06-30 Roger Sayle <[email protected]>
> >
> > gcc/ChangeLog
> > PR target/99668
> > * expr.cc (expand_expr_real_1) <case VIEW_CONVERT_EXPR>: Use
> > vec_init_optab to convert a complex number into two-component
> > vector with the same inner type.
> >
> > gcc/testsuite/ChangeLog
> > PR target/99668
> > * gcc.target/pr99668.c: New test case.
> >
> >
> > Thanks in advance,
> > Roger
> > --
> >
diff --git a/gcc/expr.cc b/gcc/expr.cc
index f42aab21272..9933286df84 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 00000000000..90bac695083
--- /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" } } */