[llvm] [RISCV] Add ComplexPatterns for matching xor/vmnot_vl+vmset_vl. NFC (PR #182071)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 18 09:31:03 PST 2026


https://github.com/topperc created https://github.com/llvm/llvm-project/pull/182071

Xor is commutable and we don't guarantee which operand will be the vmset_vl. Tablegen will generate all possible permutations when creating RISCVGenDAGISel.inc. These xor/vmnot_vl are used by other commutable nodes leading to quite a few patterns being generated by tablegen.

By using a ComplexPattern we can handle both cases with one piece of C++ code. This reduces the isel table by 2-3k.

>From 17f15124575df15c886fb60ff566c80f888d2bd4 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 17 Feb 2026 22:31:24 -0800
Subject: [PATCH] [RISCV] Add ComplexPatterns for matching
 xor/vmnot_vl+vmset_vl. NFC

Xor is commutable and we don't guarantee which operand will be the vmset_vl.
Tablegen will generate all possible permutations when creating
RISCVGenDAGISel.inc. These xor/vmnot_vl are used by other commutable
nodes leading to quite a few patterns being generated by tablegen.

By using a ComplexPattern we can handle both cases with one piece
of C++ code. This reduces the isel table by 2-3k.
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp   | 48 +++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h     |  3 ++
 .../Target/RISCV/RISCVInstrInfoVSDPatterns.td | 11 +++--
 .../Target/RISCV/RISCVInstrInfoVVLPatterns.td | 18 ++++---
 4 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index bf5057bdc50fb..f25c4b5648dac 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -4565,6 +4565,54 @@ bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width,
   return false;
 }
 
+// Match XOR with a VMSET_VL operand. REturn the other operand.
+bool RISCVDAGToDAGISel::selectVMNOTOp(SDValue N, SDValue &Res) {
+  if (N.getOpcode() != ISD::XOR)
+    return false;
+
+  if (N.getOperand(0).getOpcode() == RISCVISD::VMSET_VL) {
+    Res = N.getOperand(1);
+    return true;
+  }
+
+  if (N.getOperand(1).getOpcode() == RISCVISD::VMSET_VL) {
+    Res = N.getOperand(0);
+    return true;
+  }
+
+  return false;
+}
+
+// Match VMXOR_VL with a VMSET_VL operand. Making sure that that VL operand
+// matches the parent's VL. Return the other operand of the VMXOR_VL.
+bool RISCVDAGToDAGISel::selectVMNOT_VLOp(SDNode *Parent, SDValue N,
+                                         SDValue &Res) {
+  if (N.getOpcode() != RISCVISD::VMXOR_VL)
+    return false;
+
+  assert(Parent &&
+         (Parent->getOpcode() == RISCVISD::VMAND_VL ||
+          Parent->getOpcode() == RISCVISD::VMOR_VL ||
+          Parent->getOpcode() == RISCVISD::VMXOR_VL) &&
+         "Unexpected parent");
+
+  // The VL should match the parent.
+  if (Parent->getOperand(2) != N->getOperand(2))
+    return false;
+
+  if (N.getOperand(0).getOpcode() == RISCVISD::VMSET_VL) {
+    Res = N.getOperand(1);
+    return true;
+  }
+
+  if (N.getOperand(1).getOpcode() == RISCVISD::VMSET_VL) {
+    Res = N.getOperand(0);
+    return true;
+  }
+
+  return false;
+}
+
 // Try to remove sext.w if the input is a W instruction or can be made into
 // a W instruction cheaply.
 bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) {
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index 1d59dc57c4135..8cb4effef582c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -156,6 +156,9 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
     return selectRVVSimm5(N, Width, Imm);
   }
 
+  bool selectVMNOTOp(SDValue N, SDValue &Res);
+  bool selectVMNOT_VLOp(SDNode *Parent, SDValue N, SDValue &Res);
+
   void addVectorLoadStoreOperands(SDNode *Node, unsigned SEWImm,
                                   const SDLoc &DL, unsigned CurOp,
                                   bool IsMasked, bool IsStridedOrIndexed,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td
index a469d7a04ec36..23951fa4c6d19 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td
@@ -24,6 +24,11 @@
 def rvv_vnot : PatFrag<(ops node:$in),
                        (xor node:$in, (riscv_vmset_vl (XLenVT srcvalue)))>;
 
+// Match xor+riscv_vmset_vl as an operand. By handling as a ComplexPattern we
+// can check both operands of the xor without needing tablegen to emit
+// multiple isel patterns.
+def rvv_vnot_op : ComplexPattern<vAny, 1, "selectVMNOTOp", [xor], [], 3>;
+
 multiclass VPatUSLoadStoreSDNode<ValueType type,
                                  RegisterClass regclass,
                                  int log2sew,
@@ -1203,15 +1208,15 @@ foreach mti = AllMasks in {
               (!cast<Instruction>("PseudoVMXNOR_MM_"#mti.BX)
                    VR:$rs1, VR:$rs2, mti.AVL, mti.Log2SEW)>;
 
-    def : Pat<(mti.Mask (and VR:$rs1, (rvv_vnot VR:$rs2))),
+    def : Pat<(mti.Mask (and VR:$rs1, rvv_vnot_op:$rs2)),
               (!cast<Instruction>("PseudoVMANDN_MM_"#mti.BX)
                    VR:$rs1, VR:$rs2, mti.AVL, mti.Log2SEW)>;
-    def : Pat<(mti.Mask (or VR:$rs1, (rvv_vnot VR:$rs2))),
+    def : Pat<(mti.Mask (or VR:$rs1, rvv_vnot_op:$rs2)),
               (!cast<Instruction>("PseudoVMORN_MM_"#mti.BX)
                    VR:$rs1, VR:$rs2, mti.AVL, mti.Log2SEW)>;
 
     // Handle rvv_vnot the same as the vmnot.m pseudoinstruction.
-    def : Pat<(mti.Mask (rvv_vnot VR:$rs)),
+    def : Pat<(mti.Mask rvv_vnot_op:$rs),
               (!cast<Instruction>("PseudoVMNAND_MM_"#mti.BX)
                    VR:$rs, VR:$rs, mti.AVL, mti.Log2SEW)>;
   }
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
index d1bcaffdeac5b..0d5ba476cc88a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
@@ -493,6 +493,13 @@ def true_mask : PatLeaf<(riscv_vmset_vl (XLenVT srcvalue))>;
 def riscv_vmnot_vl : PatFrag<(ops node:$rs, node:$vl),
                              (riscv_vmxor_vl node:$rs, true_mask, node:$vl)>;
 
+// Match riscv_vmxor_vl+riscv_vmset_vl as an operand. By handling as a
+// ComplexPattern we can check both operands of the vmxor_vl without needing
+// tablegen to emit multiple isel patterns.
+def riscv_vmnot_vl_op : ComplexPattern<vAny, 1, "selectVMNOT_VLOp", [], [], 9> {
+  let WantsParent = true;
+}
+
 let HasMaskOp = true in {
   //  vcpop.m with additional mask and VL operands.
   def riscv_vcpop_vl : RVSDNode<"VCPOP_VL",
@@ -2828,20 +2835,17 @@ foreach mti = AllMasks in {
               (!cast<Instruction>("PseudoVMXOR_MM_" # mti.BX)
                    VR:$rs1, VR:$rs2, GPR:$vl, mti.Log2SEW)>;
 
-    def : Pat<(mti.Mask (riscv_vmand_vl VR:$rs1,
-                                        (riscv_vmnot_vl VR:$rs2, VLOpFrag),
+    def : Pat<(mti.Mask (riscv_vmand_vl VR:$rs1, riscv_vmnot_vl_op:$rs2,
                                         VLOpFrag)),
               (!cast<Instruction>("PseudoVMANDN_MM_" # mti.BX)
                    VR:$rs1, VR:$rs2, GPR:$vl, mti.Log2SEW)>;
-    def : Pat<(mti.Mask (riscv_vmor_vl VR:$rs1,
-                                       (riscv_vmnot_vl VR:$rs2, VLOpFrag),
+    def : Pat<(mti.Mask (riscv_vmor_vl VR:$rs1, riscv_vmnot_vl_op:$rs2,
                                        VLOpFrag)),
               (!cast<Instruction>("PseudoVMORN_MM_" # mti.BX)
                    VR:$rs1, VR:$rs2, GPR:$vl, mti.Log2SEW)>;
     // XOR is associative so we need 2 patterns for VMXNOR.
-    def : Pat<(mti.Mask (riscv_vmxor_vl (riscv_vmnot_vl VR:$rs1,
-                                                        VLOpFrag),
-                                       VR:$rs2, VLOpFrag)),
+    def : Pat<(mti.Mask (riscv_vmxor_vl riscv_vmnot_vl_op:$rs1,
+                                        VR:$rs2, VLOpFrag)),
               (!cast<Instruction>("PseudoVMXNOR_MM_" # mti.BX)
                    VR:$rs1, VR:$rs2, GPR:$vl, mti.Log2SEW)>;
 



More information about the llvm-commits mailing list