[llvm] [X86][ISel] Improve VPTERNLOG matching for negated logic trees (PR #164863)

Yi-Chi Lee via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 24 06:38:28 PDT 2025


https://github.com/yichi170 updated https://github.com/llvm/llvm-project/pull/164863

>From f66a0cb105e46692f147c453c79ef60f38b93861 Mon Sep 17 00:00:00 2001
From: Yi-Chi Lee <yichi170 at gmail.com>
Date: Thu, 23 Oct 2025 12:45:49 -0500
Subject: [PATCH 1/5] [X86][ISel] Improve VPTERNLOG matching for negated logic
 trees

---
 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 39 ++++++++++++++++++++++---
 llvm/test/CodeGen/X86/issue163738.ll    | 13 +++++++++
 2 files changed, 48 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/issue163738.ll

diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 62073ec125e8f..06a691d73c749 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -4721,9 +4721,6 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
   if (!(Subtarget->hasVLX() || NVT.is512BitVector()))
     return false;
 
-  SDValue N0 = N->getOperand(0);
-  SDValue N1 = N->getOperand(1);
-
   auto getFoldableLogicOp = [](SDValue Op) {
     // Peek through single use bitcast.
     if (Op.getOpcode() == ISD::BITCAST && Op.hasOneUse())
@@ -4740,6 +4737,37 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
     return SDValue();
   };
 
+  // Identify and (optionally) peel an outer NOT that wraps a pure logic tree
+  auto tryPeelOuterNotWrappingLogic = [&](SDNode *Op) {
+    if (Op->getOpcode() == ISD::XOR && Op->hasOneUse() &&
+        ISD::isBuildVectorAllOnes(Op->getOperand(1).getNode())) {
+      SDNode *InnerN = Op->getOperand(0).getNode();
+
+      unsigned InnerOpc = InnerN->getOpcode();
+      if (InnerOpc != ISD::AND && InnerOpc != ISD::OR &&
+          InnerOpc != ISD::XOR && InnerOpc != X86ISD::ANDNP) {
+        return Op;
+      }
+
+      SDValue InnerN0 = InnerN->getOperand(0);
+      SDValue InnerN1 = InnerN->getOperand(1);
+      SDValue FoldableOp;
+      if (getFoldableLogicOp(InnerN1) || getFoldableLogicOp(InnerN0))
+        return InnerN;
+    }
+    return Op;
+  };
+
+  SDNode *OriN = N;
+  bool PeeledOuterNot = false;
+  N = tryPeelOuterNotWrappingLogic(N);
+  if (N != OriN)
+    PeeledOuterNot = true;
+    
+
+  SDValue N0 = N->getOperand(0);
+  SDValue N1 = N->getOperand(1);
+
   SDValue A, FoldableOp;
   if ((FoldableOp = getFoldableLogicOp(N1))) {
     A = N0;
@@ -4798,7 +4826,10 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
   case ISD::XOR: Imm ^= TernlogMagicA; break;
   }
 
-  return matchVPTERNLOG(N, ParentA, ParentB, ParentC, A, B, C, Imm);
+  if (PeeledOuterNot)
+    Imm = ~Imm;
+
+  return matchVPTERNLOG(OriN, ParentA, ParentB, ParentC, A, B, C, Imm);
 }
 
 /// If the high bits of an 'and' operand are known zero, try setting the
diff --git a/llvm/test/CodeGen/X86/issue163738.ll b/llvm/test/CodeGen/X86/issue163738.ll
new file mode 100644
index 0000000000000..61fe043a970dd
--- /dev/null
+++ b/llvm/test/CodeGen/X86/issue163738.ll
@@ -0,0 +1,13 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512f,+avx512vl | FileCheck %s --check-prefixes=CHECK
+
+define <8 x i64> @foo(<8 x i64> %a, <8 x i64> %b, <8 x i64> %c) {
+; CHECK-LABEL: foo:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vpternlogq {{.*#+}} zmm0 = ~(zmm0 | zmm2 | zmm1)
+; CHECK-NEXT:    retq
+  %and.demorgan = or <8 x i64> %b, %a
+  %and3.demorgan = or <8 x i64> %and.demorgan, %c
+  %and3 = xor <8 x i64> %and3.demorgan, splat (i64 -1)
+  ret <8 x i64> %and3
+}

>From 0cc7cd915cfbd8e7b813018f458b2ff81d2fc51f Mon Sep 17 00:00:00 2001
From: Yi-Chi Lee <yichi170 at gmail.com>
Date: Thu, 23 Oct 2025 13:08:55 -0500
Subject: [PATCH 2/5] clang-format

---
 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 06a691d73c749..ab86901c262b0 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -4744,8 +4744,8 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
       SDNode *InnerN = Op->getOperand(0).getNode();
 
       unsigned InnerOpc = InnerN->getOpcode();
-      if (InnerOpc != ISD::AND && InnerOpc != ISD::OR &&
-          InnerOpc != ISD::XOR && InnerOpc != X86ISD::ANDNP) {
+      if (InnerOpc != ISD::AND && InnerOpc != ISD::OR && InnerOpc != ISD::XOR &&
+          InnerOpc != X86ISD::ANDNP) {
         return Op;
       }
 
@@ -4763,7 +4763,6 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
   N = tryPeelOuterNotWrappingLogic(N);
   if (N != OriN)
     PeeledOuterNot = true;
-    
 
   SDValue N0 = N->getOperand(0);
   SDValue N1 = N->getOperand(1);

>From 6aafdb037054b8cfb5c6abb45fc2513eebf19aae Mon Sep 17 00:00:00 2001
From: Yi-Chi Lee <yichi170 at gmail.com>
Date: Thu, 23 Oct 2025 13:23:48 -0500
Subject: [PATCH 3/5] remove unused variable

---
 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index ab86901c262b0..a4fd9be80e194 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -4751,7 +4751,6 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
 
       SDValue InnerN0 = InnerN->getOperand(0);
       SDValue InnerN1 = InnerN->getOperand(1);
-      SDValue FoldableOp;
       if (getFoldableLogicOp(InnerN1) || getFoldableLogicOp(InnerN0))
         return InnerN;
     }

>From 9092c7e8d8ab4bf03ffc864113cd3b9cf3ed9e96 Mon Sep 17 00:00:00 2001
From: Yi-Chi Lee <yichi170 at gmail.com>
Date: Thu, 23 Oct 2025 23:12:56 -0500
Subject: [PATCH 4/5] address some comments

---
 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index a4fd9be80e194..eb28be708a9cf 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -4741,27 +4741,26 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
   auto tryPeelOuterNotWrappingLogic = [&](SDNode *Op) {
     if (Op->getOpcode() == ISD::XOR && Op->hasOneUse() &&
         ISD::isBuildVectorAllOnes(Op->getOperand(1).getNode())) {
-      SDNode *InnerN = Op->getOperand(0).getNode();
+      SDValue InnerOp = Op->getOperand(0);
 
-      unsigned InnerOpc = InnerN->getOpcode();
-      if (InnerOpc != ISD::AND && InnerOpc != ISD::OR && InnerOpc != ISD::XOR &&
-          InnerOpc != X86ISD::ANDNP) {
-        return Op;
+      if (!getFoldableLogicOp(InnerOp)) {
+        return SDValue();
       }
 
-      SDValue InnerN0 = InnerN->getOperand(0);
-      SDValue InnerN1 = InnerN->getOperand(1);
+      SDValue InnerN0 = InnerOp.getOperand(0);
+      SDValue InnerN1 = InnerOp.getOperand(1);
       if (getFoldableLogicOp(InnerN1) || getFoldableLogicOp(InnerN0))
-        return InnerN;
+        return InnerOp;
     }
-    return Op;
+    return SDValue();
   };
 
-  SDNode *OriN = N;
   bool PeeledOuterNot = false;
-  N = tryPeelOuterNotWrappingLogic(N);
-  if (N != OriN)
+  SDNode *OriN = N;
+  if (SDValue InnerOp = tryPeelOuterNotWrappingLogic(N)) {
     PeeledOuterNot = true;
+    N = InnerOp.getNode();
+  }
 
   SDValue N0 = N->getOperand(0);
   SDValue N1 = N->getOperand(1);

>From 97201e72d58fc7ee2f3f394f6607fdc11e143ea2 Mon Sep 17 00:00:00 2001
From: Yi-Chi Lee <yichi170 at gmail.com>
Date: Fri, 24 Oct 2025 08:36:50 -0500
Subject: [PATCH 5/5] address comments

---
 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 38 ++++++++++++++-----------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index eb28be708a9cf..4393f6ecaa033 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -4737,20 +4737,27 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
     return SDValue();
   };
 
+  SDValue N0, N1, A, FoldableOp;
+
   // Identify and (optionally) peel an outer NOT that wraps a pure logic tree
   auto tryPeelOuterNotWrappingLogic = [&](SDNode *Op) {
     if (Op->getOpcode() == ISD::XOR && Op->hasOneUse() &&
         ISD::isBuildVectorAllOnes(Op->getOperand(1).getNode())) {
       SDValue InnerOp = Op->getOperand(0);
 
-      if (!getFoldableLogicOp(InnerOp)) {
+      if (!getFoldableLogicOp(InnerOp))
         return SDValue();
-      }
 
-      SDValue InnerN0 = InnerOp.getOperand(0);
-      SDValue InnerN1 = InnerOp.getOperand(1);
-      if (getFoldableLogicOp(InnerN1) || getFoldableLogicOp(InnerN0))
+      N0 = InnerOp.getOperand(0);
+      N1 = InnerOp.getOperand(1);
+      if ((FoldableOp = getFoldableLogicOp(N1))) {
+        A = N0;
+        return InnerOp;
+      }
+      if ((FoldableOp = getFoldableLogicOp(N0))) {
+        A = N1;
         return InnerOp;
+      }
     }
     return SDValue();
   };
@@ -4760,18 +4767,17 @@ bool X86DAGToDAGISel::tryVPTERNLOG(SDNode *N) {
   if (SDValue InnerOp = tryPeelOuterNotWrappingLogic(N)) {
     PeeledOuterNot = true;
     N = InnerOp.getNode();
-  }
-
-  SDValue N0 = N->getOperand(0);
-  SDValue N1 = N->getOperand(1);
+  } else {
+    N0 = N->getOperand(0);
+    N1 = N->getOperand(1);
 
-  SDValue A, FoldableOp;
-  if ((FoldableOp = getFoldableLogicOp(N1))) {
-    A = N0;
-  } else if ((FoldableOp = getFoldableLogicOp(N0))) {
-    A = N1;
-  } else
-    return false;
+    if ((FoldableOp = getFoldableLogicOp(N1)))
+      A = N0;
+    else if ((FoldableOp = getFoldableLogicOp(N0)))
+      A = N1;
+    else
+      return false;
+  }
 
   SDValue B = FoldableOp.getOperand(0);
   SDValue C = FoldableOp.getOperand(1);



More information about the llvm-commits mailing list