[llvm] [NFC][DecoderEmitter] Predicate generation code cleanup (PR #158140)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 15 18:20:50 PDT 2025


https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/158140

>From ae4f93602ce9865876c459b17128ad4b9a9c1d0a Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 11 Sep 2025 12:33:42 -0700
Subject: [PATCH 1/5] [NFC][DecoderEmitter] Predicate generation code cleanup

Use `ListSeparator` to join individual predicated with `&&`.
Eliminate `doesOpcodeNeedPredicate` and instead have
`emitPredicateMatch` return true if any predicates were generated.
---
 llvm/utils/TableGen/DecoderEmitter.cpp | 32 ++++++--------------------
 1 file changed, 7 insertions(+), 25 deletions(-)

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 1829f05432e3b..14e24bd44f8c2 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -519,8 +519,6 @@ class DecoderTableBuilder {
 
   bool emitPredicateMatch(raw_ostream &OS, unsigned EncodingID) const;
 
-  bool doesOpcodeNeedPredicate(unsigned EncodingID) const;
-
   void emitPredicateTableEntry(unsigned EncodingID) const;
 
   void emitSoftFailTableEntry(unsigned EncodingID) const;
@@ -1138,7 +1136,8 @@ bool DecoderTableBuilder::emitPredicateMatch(raw_ostream &OS,
                                              unsigned EncodingID) const {
   const ListInit *Predicates =
       Encodings[EncodingID].getRecord()->getValueAsListInit("Predicates");
-  bool IsFirstEmission = true;
+  ListSeparator LS(" && ");
+  bool AnyPredicate = false;
   for (unsigned i = 0; i < Predicates->size(); ++i) {
     const Record *Pred = Predicates->getElementAsRecord(i);
     if (!Pred->getValue("AssemblerMatcherPredicate"))
@@ -1147,28 +1146,13 @@ bool DecoderTableBuilder::emitPredicateMatch(raw_ostream &OS,
     if (!isa<DagInit>(Pred->getValue("AssemblerCondDag")->getValue()))
       continue;
 
-    if (!IsFirstEmission)
-      OS << " && ";
+    AnyPredicate = true;
+    OS << LS;
     if (emitPredicateMatchAux(*Pred->getValueAsDag("AssemblerCondDag"),
                               Predicates->size() > 1, OS))
       PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!");
-    IsFirstEmission = false;
-  }
-  return !Predicates->empty();
-}
-
-bool DecoderTableBuilder::doesOpcodeNeedPredicate(unsigned EncodingID) const {
-  const ListInit *Predicates =
-      Encodings[EncodingID].getRecord()->getValueAsListInit("Predicates");
-  for (unsigned i = 0; i < Predicates->size(); ++i) {
-    const Record *Pred = Predicates->getElementAsRecord(i);
-    if (!Pred->getValue("AssemblerMatcherPredicate"))
-      continue;
-
-    if (isa<DagInit>(Pred->getValue("AssemblerCondDag")->getValue()))
-      return true;
   }
-  return false;
+  return AnyPredicate;
 }
 
 unsigned DecoderTableBuilder::getPredicateIndex(StringRef Predicate) const {
@@ -1186,15 +1170,13 @@ unsigned DecoderTableBuilder::getPredicateIndex(StringRef Predicate) const {
 }
 
 void DecoderTableBuilder::emitPredicateTableEntry(unsigned EncodingID) const {
-  if (!doesOpcodeNeedPredicate(EncodingID))
-    return;
-
   // Build up the predicate string.
   SmallString<256> Predicate;
   // FIXME: emitPredicateMatch() functions can take a buffer directly rather
   // than a stream.
   raw_svector_ostream PS(Predicate);
-  emitPredicateMatch(PS, EncodingID);
+  if (!emitPredicateMatch(PS, EncodingID))
+    return;
 
   // Figure out the index into the predicate table for the predicate just
   // computed.

>From 62a1ea2794ef3ff72e6d990fddc4ba7fa7c399ee Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Sun, 14 Sep 2025 07:01:35 -0700
Subject: [PATCH 2/5] Review feedback

---
 .../TableGen/Common/SubtargetFeatureInfo.cpp  | 15 +++++---
 llvm/utils/TableGen/DecoderEmitter.cpp        | 38 +++++++------------
 2 files changed, 23 insertions(+), 30 deletions(-)

diff --git a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
index bd8af32ee5096..5239287853322 100644
--- a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
@@ -190,8 +190,9 @@ void SubtargetFeatureInfo::emitMCPredicateCheck(
   bool ParenIfBinOp = range_size(MCPredicates) > 1;
   for (const Record *R : MCPredicates) {
     OS << LS;
-    emitFeaturesAux(TargetName, *R->getValueAsDag("AssemblerCondDag"),
-                    ParenIfBinOp, OS);
+    if (emitFeaturesAux(TargetName, *R->getValueAsDag("AssemblerCondDag"),
+                    ParenIfBinOp, OS))
+      PrintFatalError(R, "Invalid AssemblerCondDag!");
   }
 }
 
@@ -206,12 +207,14 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
     OS << "const ";
   OS << "{\n";
   OS << "  FeatureBitset Features;\n";
-  for (const auto &SF : SubtargetFeatures) {
-    const SubtargetFeatureInfo &SFI = SF.second;
+  for (const SubtargetFeatureInfo &SFI : make_second_range(SubtargetFeatures)) {
+    const Record *Def = SFI.TheDef;
 
     OS << "  if (";
-    emitFeaturesAux(TargetName, *SFI.TheDef->getValueAsDag("AssemblerCondDag"),
-                    /*ParenIfBinOp=*/false, OS);
+    if (emitFeaturesAux(TargetName, *Def->getValueAsDag("AssemblerCondDag"),
+                    /*ParenIfBinOp=*/false, OS))
+      PrintFatalError(Def, "Invalid AssemblerCondDag!");
+
     OS << ")\n";
     OS << "    Features.set(" << SFI.getEnumBitName() << ");\n";
   }
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 14e24bd44f8c2..76140d9170f96 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -17,6 +17,7 @@
 #include "Common/InfoByHwMode.h"
 #include "Common/InstructionEncoding.h"
 #include "Common/VarLenCodeEmitterGen.h"
+#include "Common/SubtargetFeatureInfo.h"
 #include "TableGenBackends.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -517,7 +518,7 @@ class DecoderTableBuilder {
   bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp,
                              raw_ostream &OS) const;
 
-  bool emitPredicateMatch(raw_ostream &OS, unsigned EncodingID) const;
+  void emitPredicateMatch(raw_ostream &OS, unsigned EncodingID) const;
 
   void emitPredicateTableEntry(unsigned EncodingID) const;
 
@@ -837,7 +838,7 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
   // The predicate function is just a big switch statement based on the
   // input predicate index.
   OS << "static bool checkDecoderPredicate(unsigned Idx, const FeatureBitset "
-        "&Bits) {\n";
+        "&FB) {\n";
   OS << "  switch (Idx) {\n";
   OS << "  default: llvm_unreachable(\"Invalid index!\");\n";
   for (const auto &[Index, Predicate] : enumerate(Predicates)) {
@@ -1132,27 +1133,14 @@ bool DecoderTableBuilder::emitPredicateMatchAux(const Init &Val,
   return true;
 }
 
-bool DecoderTableBuilder::emitPredicateMatch(raw_ostream &OS,
+void DecoderTableBuilder::emitPredicateMatch(raw_ostream &OS,
                                              unsigned EncodingID) const {
-  const ListInit *Predicates =
+  const ListInit *PredicateList =
       Encodings[EncodingID].getRecord()->getValueAsListInit("Predicates");
-  ListSeparator LS(" && ");
-  bool AnyPredicate = false;
-  for (unsigned i = 0; i < Predicates->size(); ++i) {
-    const Record *Pred = Predicates->getElementAsRecord(i);
-    if (!Pred->getValue("AssemblerMatcherPredicate"))
-      continue;
-
-    if (!isa<DagInit>(Pred->getValue("AssemblerCondDag")->getValue()))
-      continue;
-
-    AnyPredicate = true;
-    OS << LS;
-    if (emitPredicateMatchAux(*Pred->getValueAsDag("AssemblerCondDag"),
-                              Predicates->size() > 1, OS))
-      PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!");
-  }
-  return AnyPredicate;
+  std::vector<const Record *> Predicates;
+  for (unsigned i = 0; i < PredicateList->size(); ++i)
+    Predicates.push_back(PredicateList->getElementAsRecord(i));
+  SubtargetFeatureInfo::emitMCPredicateCheck(OS, Target.getName(), Predicates);
 }
 
 unsigned DecoderTableBuilder::getPredicateIndex(StringRef Predicate) const {
@@ -1172,10 +1160,12 @@ unsigned DecoderTableBuilder::getPredicateIndex(StringRef Predicate) const {
 void DecoderTableBuilder::emitPredicateTableEntry(unsigned EncodingID) const {
   // Build up the predicate string.
   SmallString<256> Predicate;
-  // FIXME: emitPredicateMatch() functions can take a buffer directly rather
-  // than a stream.
   raw_svector_ostream PS(Predicate);
-  if (!emitPredicateMatch(PS, EncodingID))
+  emitPredicateMatch(PS, EncodingID);
+  // Predicate being empty indicates that there are no predicates.
+  // Predicate being "false" indicate that there are predicates but with no
+  // AssemblerMatcherPredicate.
+  if (Predicate.empty() || Predicate == "false")
     return;
 
   // Figure out the index into the predicate table for the predicate just

>From 29a68757b2ac7b6e82819e782ebfed7875825f44 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Sun, 14 Sep 2025 17:14:40 -0700
Subject: [PATCH 3/5] Drop outer ()

---
 llvm/test/TableGen/AsmPredicateCombining.td     | 10 +++++-----
 llvm/test/TableGen/AsmPredicateCondsEmission.td |  2 +-
 llvm/utils/TableGen/DecoderEmitter.cpp          |  2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/test/TableGen/AsmPredicateCombining.td b/llvm/test/TableGen/AsmPredicateCombining.td
index c8081a428d7bb..c86bb9dc24330 100644
--- a/llvm/test/TableGen/AsmPredicateCombining.td
+++ b/llvm/test/TableGen/AsmPredicateCombining.td
@@ -63,19 +63,19 @@ def AsmPred4 : Predicate<"Pred4">, AssemblerPredicate<(all_of AsmCond4, (not (an
 // MATCHER-NEXT:   Features.set(Feature_AsmPred4Bit);
 
 def insn1 : TestInsn<1, [AsmPred1]>;
-// DISASS: return (Bits[arch::AsmCond1]);
+// DISASS: return FB[arch::AsmCond1]
 
 def insn2 : TestInsn<2, [AsmPred2]>;
-// DISASS: return (Bits[arch::AsmCond2a] && Bits[arch::AsmCond2b])
+// DISASS: return FB[arch::AsmCond2a] && FB[arch::AsmCond2b]
 
 def insn3 : TestInsn<3, [AsmPred3]>;
-// DISASS: return (Bits[arch::AsmCond3a] || Bits[arch::AsmCond3b])
+// DISASS: return FB[arch::AsmCond3a] || FB[arch::AsmCond3b]
 
 def insn4 : TestInsn<4, [AsmPred1, AsmPred2]>;
-// DISASS: return (Bits[arch::AsmCond1] && (Bits[arch::AsmCond2a] && Bits[arch::AsmCond2b]))
+// DISASS: return FB[arch::AsmCond1] && (FB[arch::AsmCond2a] && FB[arch::AsmCond2b])
 
 def insn5 : TestInsn<5, [AsmPred1, AsmPred3]>;
-// DISASS: return (Bits[arch::AsmCond1] && (Bits[arch::AsmCond3a] || Bits[arch::AsmCond3b]))
+// DISASS: return FB[arch::AsmCond1] && (FB[arch::AsmCond3a] || FB[arch::AsmCond3b])
 
 def insn6 : TestInsn<6, []>;
 def : InstAlias<"alias1", (insn6 R0)> { let Predicates = [AsmPred1]; }
diff --git a/llvm/test/TableGen/AsmPredicateCondsEmission.td b/llvm/test/TableGen/AsmPredicateCondsEmission.td
index 7b2ab2afa5a8d..25bc1ab95a14f 100644
--- a/llvm/test/TableGen/AsmPredicateCondsEmission.td
+++ b/llvm/test/TableGen/AsmPredicateCondsEmission.td
@@ -29,4 +29,4 @@ def foo : Instruction {
   let Predicates = [Pred1, Pred2];
 }
 
-// CHECK: return (Bits[arch::AssemblerCondition2]);
+// CHECK: return FB[arch::AssemblerCondition2];
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 76140d9170f96..f526d4a44658e 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -843,7 +843,7 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
   OS << "  default: llvm_unreachable(\"Invalid index!\");\n";
   for (const auto &[Index, Predicate] : enumerate(Predicates)) {
     OS << "  case " << Index << ":\n";
-    OS << "    return (" << Predicate << ");\n";
+    OS << "    return " << Predicate << ";\n";
   }
   OS << "  }\n";
   OS << "}\n\n";

>From 139f7f2d94736744a99575a9a10a076ea280491c Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Mon, 15 Sep 2025 09:32:45 -0700
Subject: [PATCH 4/5] Clang-format fixes

---
 llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp | 4 ++--
 llvm/utils/TableGen/DecoderEmitter.cpp              | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
index 5239287853322..a426bf4ef4b77 100644
--- a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
@@ -191,7 +191,7 @@ void SubtargetFeatureInfo::emitMCPredicateCheck(
   for (const Record *R : MCPredicates) {
     OS << LS;
     if (emitFeaturesAux(TargetName, *R->getValueAsDag("AssemblerCondDag"),
-                    ParenIfBinOp, OS))
+                        ParenIfBinOp, OS))
       PrintFatalError(R, "Invalid AssemblerCondDag!");
   }
 }
@@ -212,7 +212,7 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
 
     OS << "  if (";
     if (emitFeaturesAux(TargetName, *Def->getValueAsDag("AssemblerCondDag"),
-                    /*ParenIfBinOp=*/false, OS))
+                        /*ParenIfBinOp=*/false, OS))
       PrintFatalError(Def, "Invalid AssemblerCondDag!");
 
     OS << ")\n";
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index f526d4a44658e..25fd475f6c4e9 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -16,8 +16,8 @@
 #include "Common/CodeGenTarget.h"
 #include "Common/InfoByHwMode.h"
 #include "Common/InstructionEncoding.h"
-#include "Common/VarLenCodeEmitterGen.h"
 #include "Common/SubtargetFeatureInfo.h"
+#include "Common/VarLenCodeEmitterGen.h"
 #include "TableGenBackends.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"

>From 328f1f3b8aca58f4aa89a2d471ac069ae27623af Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Mon, 15 Sep 2025 18:18:32 -0700
Subject: [PATCH 5/5] Review feedback

---
 llvm/test/TableGen/AsmPredicateCombining.td |  8 +++----
 llvm/utils/TableGen/DecoderEmitter.cpp      | 25 +++++++++++----------
 2 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/llvm/test/TableGen/AsmPredicateCombining.td b/llvm/test/TableGen/AsmPredicateCombining.td
index c86bb9dc24330..32ea992bf1c06 100644
--- a/llvm/test/TableGen/AsmPredicateCombining.td
+++ b/llvm/test/TableGen/AsmPredicateCombining.td
@@ -66,16 +66,16 @@ def insn1 : TestInsn<1, [AsmPred1]>;
 // DISASS: return FB[arch::AsmCond1]
 
 def insn2 : TestInsn<2, [AsmPred2]>;
-// DISASS: return FB[arch::AsmCond2a] && FB[arch::AsmCond2b]
+// DISASS: return FB[arch::AsmCond2a] && FB[arch::AsmCond2b];
 
 def insn3 : TestInsn<3, [AsmPred3]>;
-// DISASS: return FB[arch::AsmCond3a] || FB[arch::AsmCond3b]
+// DISASS: return FB[arch::AsmCond3a] || FB[arch::AsmCond3b];
 
 def insn4 : TestInsn<4, [AsmPred1, AsmPred2]>;
-// DISASS: return FB[arch::AsmCond1] && (FB[arch::AsmCond2a] && FB[arch::AsmCond2b])
+// DISASS: return FB[arch::AsmCond1] && (FB[arch::AsmCond2a] && FB[arch::AsmCond2b]);
 
 def insn5 : TestInsn<5, [AsmPred1, AsmPred3]>;
-// DISASS: return FB[arch::AsmCond1] && (FB[arch::AsmCond3a] || FB[arch::AsmCond3b])
+// DISASS: return FB[arch::AsmCond1] && (FB[arch::AsmCond3a] || FB[arch::AsmCond3b]);
 
 def insn6 : TestInsn<6, []>;
 def : InstAlias<"alias1", (insn6 R0)> { let Predicates = [AsmPred1]; }
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 25fd475f6c4e9..97a6b58e1bd99 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -518,7 +518,7 @@ class DecoderTableBuilder {
   bool emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp,
                              raw_ostream &OS) const;
 
-  void emitPredicateMatch(raw_ostream &OS, unsigned EncodingID) const;
+  bool emitPredicateMatch(raw_ostream &OS, unsigned EncodingID) const;
 
   void emitPredicateTableEntry(unsigned EncodingID) const;
 
@@ -1133,14 +1133,19 @@ bool DecoderTableBuilder::emitPredicateMatchAux(const Init &Val,
   return true;
 }
 
-void DecoderTableBuilder::emitPredicateMatch(raw_ostream &OS,
+// Returns true if there was any predicate emitted.
+bool DecoderTableBuilder::emitPredicateMatch(raw_ostream &OS,
                                              unsigned EncodingID) const {
-  const ListInit *PredicateList =
-      Encodings[EncodingID].getRecord()->getValueAsListInit("Predicates");
-  std::vector<const Record *> Predicates;
-  for (unsigned i = 0; i < PredicateList->size(); ++i)
-    Predicates.push_back(PredicateList->getElementAsRecord(i));
+  std::vector<const Record *> Predicates =
+      Encodings[EncodingID].getRecord()->getValueAsListOfDefs("Predicates");
+  auto It = llvm::find_if(Predicates, [](const Record *R) {
+    return R->getValueAsBit("AssemblerMatcherPredicate");
+  });
+  bool AnyAsmPredicate = It != Predicates.end();
+  if (!AnyAsmPredicate)
+    return false;
   SubtargetFeatureInfo::emitMCPredicateCheck(OS, Target.getName(), Predicates);
+  return true;
 }
 
 unsigned DecoderTableBuilder::getPredicateIndex(StringRef Predicate) const {
@@ -1161,11 +1166,7 @@ void DecoderTableBuilder::emitPredicateTableEntry(unsigned EncodingID) const {
   // Build up the predicate string.
   SmallString<256> Predicate;
   raw_svector_ostream PS(Predicate);
-  emitPredicateMatch(PS, EncodingID);
-  // Predicate being empty indicates that there are no predicates.
-  // Predicate being "false" indicate that there are predicates but with no
-  // AssemblerMatcherPredicate.
-  if (Predicate.empty() || Predicate == "false")
+  if (!emitPredicateMatch(PS, EncodingID))
     return;
 
   // Figure out the index into the predicate table for the predicate just



More information about the llvm-commits mailing list