[llvm] [ComplexDeinterleaving] Add missing negated fcmla matches (PR #217901)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 05:30:08 PDT 2026


https://github.com/matteo-rm created https://github.com/llvm/llvm-project/pull/217901

`identifyNodeWithImplicitAdd` currently only matches float Neg ops for 1 out of 4 possible angles, thus missing potential fcmla matches. This PR fixes it by using the already present `isNeg` util for all 4 cases. This also makes the checks more consistent.

Followup of #217650 

>From 8654a1984505b005d13a82a4b92e7d3633035f24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matt=C3=A9o=20Rizza=20Murgier?=
 <matteo.rizza-murgier at sipearl.com>
Date: Fri, 21 Aug 2026 08:58:12 +0200
Subject: [PATCH] [ComplexDeinterleaving] Add missing negated fcmla matches

---
 .../lib/CodeGen/ComplexDeinterleavingPass.cpp | 13 ++++-----
 .../complex-deinterleaving-negation.ll        | 28 +++++++++++++++++++
 2 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/CodeGen/ComplexDeinterleavingPass.cpp b/llvm/lib/CodeGen/ComplexDeinterleavingPass.cpp
index b02987dec3776..38e1043aa9614 100644
--- a/llvm/lib/CodeGen/ComplexDeinterleavingPass.cpp
+++ b/llvm/lib/CodeGen/ComplexDeinterleavingPass.cpp
@@ -656,23 +656,22 @@ ComplexDeinterleavingGraph::identifyNodeWithImplicitAdd(
   // A +/+ has a rotation of 0. If any of the operands are fneg, we flip the
   // rotations and use the operand.
   unsigned Negs = 0;
-  Value *Op;
-  if (match(R0, m_Neg(m_Value(Op)))) {
+  if (isNeg(R0)) {
     Negs |= 1;
-    R0 = Op;
-  } else if (match(R1, m_Neg(m_Value(Op)))) {
+    R0 = getNegOperand(R0);
+  } else if (isNeg(R1)) {
     Negs |= 1;
-    R1 = Op;
+    R1 = getNegOperand(R1);
   }
 
   if (isNeg(I0)) {
     Negs |= 2;
     Negs ^= 1;
     I0 = getNegOperand(I0);
-  } else if (match(I1, m_Neg(m_Value(Op)))) {
+  } else if (isNeg(I1)) {
     Negs |= 2;
     Negs ^= 1;
-    I1 = Op;
+    I1 = getNegOperand(I1);
   }
 
   ComplexDeinterleavingRotation Rotation = (ComplexDeinterleavingRotation)Negs;
diff --git a/llvm/test/CodeGen/AArch64/complex-deinterleaving-negation.ll b/llvm/test/CodeGen/AArch64/complex-deinterleaving-negation.ll
index f590805fd9ed5..c635f9d59c4e2 100644
--- a/llvm/test/CodeGen/AArch64/complex-deinterleaving-negation.ll
+++ b/llvm/test/CodeGen/AArch64/complex-deinterleaving-negation.ll
@@ -32,3 +32,31 @@ entry:
   %interleaved = shufflevector <2 x double> %real, <2 x double> %imag, <4 x i32> <i32 0, i32 2, i32 1, i32 3>
   ret <4 x double> %interleaved
 }
+
+define <4 x double> @complex_mul_negated_real_operand(<4 x double> %a, <4 x double> %b) {
+; CHECK-LABEL: complex_mul_negated_real_operand:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    movi v4.2d, #0000000000000000
+; CHECK-NEXT:    movi v5.2d, #0000000000000000
+; CHECK-NEXT:    fcmla v5.2d, v2.2d, v0.2d, #90
+; CHECK-NEXT:    fcmla v4.2d, v3.2d, v1.2d, #90
+; CHECK-NEXT:    fcmla v5.2d, v2.2d, v0.2d, #0
+; CHECK-NEXT:    fcmla v4.2d, v3.2d, v1.2d, #0
+; CHECK-NEXT:    mov v0.16b, v5.16b
+; CHECK-NEXT:    mov v1.16b, v4.16b
+; CHECK-NEXT:    ret
+entry:
+  %a.real = shufflevector <4 x double> %a, <4 x double> poison, <2 x i32> <i32 0, i32 2>
+  %a.imag = shufflevector <4 x double> %a, <4 x double> poison, <2 x i32> <i32 1, i32 3>
+  %b.real = shufflevector <4 x double> %b, <4 x double> poison, <2 x i32> <i32 0, i32 2>
+  %b.imag = shufflevector <4 x double> %b, <4 x double> poison, <2 x i32> <i32 1, i32 3>
+  %neg.a.imag = fneg contract <2 x double> %a.imag
+  %real.0 = fmul contract <2 x double> %neg.a.imag, %b.imag
+  %real.1 = fmul contract <2 x double> %a.real, %b.real
+  %real = fadd contract <2 x double> %real.0, %real.1
+  %imag.0 = fmul contract <2 x double> %a.real, %b.imag
+  %imag.1 = fmul contract <2 x double> %a.imag, %b.real
+  %imag = fadd contract <2 x double> %imag.0, %imag.1
+  %interleaved = shufflevector <2 x double> %real, <2 x double> %imag, <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+  ret <4 x double> %interleaved
+}



More information about the llvm-commits mailing list