[llvm] [TableGen][DecoderEmitter] Analyze encodings once (PR #154309)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 19 04:15:44 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tablegen

Author: Sergei Barannikov (s-barannikov)

<details>
<summary>Changes</summary>

Follow-up to #<!-- -->154288.

With HwModes involved, we used to analyze the same encoding multiple times (unless `-suppress-per-hwmode-duplicates=O2` is specified). This affected the build time and made the statistics inaccurate.

>From the point of view of the generated code, this is an NFC.

---
Full diff: https://github.com/llvm/llvm-project/pull/154309.diff


1 Files Affected:

- (modified) llvm/utils/TableGen/DecoderEmitter.cpp (+87-34) 


``````````diff
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index abf29f9d7beb9..ab67fc03ee057 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -1472,7 +1472,6 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
                                                       ? MCD::OPC_TryDecodeOrFail
                                                       : MCD::OPC_TryDecode);
   TableInfo.Table.push_back(DecoderOp);
-  NumEncodingsSupported++;
   const Record *InstDef = Encodings[EncodingID].Inst->TheDef;
   TableInfo.Table.insertULEB128(Emitter->getTarget().getInstrIntValue(InstDef));
   TableInfo.Table.insertULEB128(DIdx);
@@ -2457,6 +2456,41 @@ void DecoderEmitter::handleHwModesUnrelatedEncodings(
   }
 }
 
+/// Checks if the given target-specific non-pseudo instruction
+/// is a candidate for decoding.
+static bool isDecodableInstruction(const Record *InstDef) {
+  return !InstDef->getValueAsBit("isAsmParserOnly") &&
+         !InstDef->getValueAsBit("isCodeGenOnly");
+}
+
+/// Checks if the given encoding is valid.
+static bool isValidEncoding(const Record *EncodingDef) {
+  const RecordVal *InstField = EncodingDef->getValue("Inst");
+  if (!InstField)
+    return false;
+
+  if (const auto *InstInit = dyn_cast<BitsInit>(InstField->getValue())) {
+    // Fixed-length encoding. Size must be non-zero.
+    if (!EncodingDef->getValueAsInt("Size"))
+      return false;
+
+    // At least one of the encoding bits must be complete (not '?').
+    return !InstInit->allInComplete();
+  }
+
+  if (const auto *InstInit = dyn_cast<DagInit>(InstField->getValue())) {
+    // Variable-length encoding.
+    // At least one of the encoding bits must be complete (not '?').
+    VarLenInst VLI(InstInit, InstField);
+    return !all_of(VLI, [](const EncodingSegment &S) {
+      return isa<UnsetInit>(S.Value);
+    });
+  }
+
+  // Inst field is neither BitsInit nor DagInit. This is something unsupported.
+  return false;
+}
+
 /// Parses all InstructionEncoding instances and fills internal data structures.
 void DecoderEmitter::parseInstructionEncodings() {
   // First, collect all encoding-related HwModes referenced by the target.
@@ -2468,19 +2502,34 @@ void DecoderEmitter::parseInstructionEncodings() {
   if (HwModeIDs.empty())
     HwModeIDs.push_back(DefaultMode);
 
-  ArrayRef<const CodeGenInstruction *> Instructions = Target.getInstructions();
+  ArrayRef<const CodeGenInstruction *> Instructions =
+      Target.getTargetNonPseudoInstructions();
   Encodings.reserve(Instructions.size());
-  NumInstructions = Instructions.size();
 
   for (const CodeGenInstruction *Inst : Instructions) {
     const Record *InstDef = Inst->TheDef;
+    if (!isDecodableInstruction(InstDef)) {
+      ++NumEncodingsLackingDisasm;
+      continue;
+    }
+
     if (const Record *RV = InstDef->getValueAsOptionalDef("EncodingInfos")) {
       EncodingInfoByHwMode EBM(RV, CGH);
       for (auto [HwModeID, EncodingDef] : EBM) {
+        if (!isValidEncoding(EncodingDef)) {
+          // TODO: Should probably give a warning.
+          ++NumEncodingsOmitted;
+          continue;
+        }
         unsigned EncodingID = Encodings.size();
         Encodings.emplace_back(EncodingDef, Inst);
         EncodingIDsByHwMode[HwModeID].push_back(EncodingID);
       }
+      continue; // Ignore encoding specified by Instruction itself.
+    }
+
+    if (!isValidEncoding(InstDef)) {
+      ++NumEncodingsOmitted;
       continue;
     }
 
@@ -2496,8 +2545,24 @@ void DecoderEmitter::parseInstructionEncodings() {
   for (const Record *EncodingDef :
        RK.getAllDerivedDefinitions("AdditionalEncoding")) {
     const Record *InstDef = EncodingDef->getValueAsDef("AliasOf");
+    // TODO: Should probably give a warning in these cases.
+    //   What's the point of specifying an additional encoding
+    //   if it is invalid or if the instruction is not decodable?
+    if (!isDecodableInstruction(InstDef)) {
+      ++NumEncodingsLackingDisasm;
+      continue;
+    }
+    if (!isValidEncoding(EncodingDef)) {
+      ++NumEncodingsOmitted;
+      continue;
+    }
     Encodings.emplace_back(EncodingDef, &Target.getInstruction(InstDef));
   }
+
+  // Do some statistics.
+  NumInstructions = Instructions.size();
+  NumEncodingsSupported = Encodings.size();
+  NumEncodings = NumEncodingsSupported + NumEncodingsOmitted;
 }
 
 DecoderEmitter::DecoderEmitter(const RecordKeeper &RK,
@@ -2528,9 +2593,6 @@ namespace {
   emitInsertBits(OS);
   emitCheck(OS);
 
-  // Map of (namespace, hwmode, size) tuple to encoding IDs.
-  std::map<std::tuple<StringRef, unsigned, unsigned>, std::vector<unsigned>>
-      EncMap;
   std::map<unsigned, std::vector<OperandInfo>> Operands;
   std::vector<unsigned> InstrLen;
   bool IsVarLenInst = Target.hasVariableLengthEncodings();
@@ -2538,39 +2600,30 @@ namespace {
     InstrLen.resize(Target.getInstructions().size(), 0);
   unsigned MaxInstLen = 0;
 
+  for (auto [EncodingID, Encoding] : enumerate(Encodings)) {
+    const Record *EncodingDef = Encoding.EncodingDef;
+    const CodeGenInstruction *Inst = Encoding.Inst;
+    unsigned BitWidth =
+        populateInstruction(Target, *EncodingDef, *Inst, EncodingID,
+                            Operands, IsVarLenInst);
+    assert(BitWidth && "Invalid encodings should have been filtered out");
+    if (IsVarLenInst) {
+      MaxInstLen = std::max(MaxInstLen, BitWidth);
+      InstrLen[Target.getInstrIntValue(Inst->TheDef)] = BitWidth;
+    }
+  }
+
+  // Map of (namespace, hwmode, size) tuple to encoding IDs.
+  std::map<std::tuple<StringRef, unsigned, unsigned>, std::vector<unsigned>>
+      EncMap;
   for (const auto &[HwModeID, EncodingIDs] : EncodingIDsByHwMode) {
     for (unsigned EncodingID : EncodingIDs) {
       const EncodingAndInst &Encoding = Encodings[EncodingID];
       const Record *EncodingDef = Encoding.EncodingDef;
-      const CodeGenInstruction *Inst = Encoding.Inst;
-      const Record *Def = Inst->TheDef;
       unsigned Size = EncodingDef->getValueAsInt("Size");
-      if (Def->getValueAsString("Namespace") == "TargetOpcode" ||
-          Def->getValueAsBit("isPseudo") ||
-          Def->getValueAsBit("isAsmParserOnly") ||
-          Def->getValueAsBit("isCodeGenOnly")) {
-        NumEncodingsLackingDisasm++;
-        continue;
-      }
-
-      NumEncodings++;
-
-      if (!Size && !IsVarLenInst)
-        continue;
-
-      if (unsigned Len =
-              populateInstruction(Target, *EncodingDef, *Inst, EncodingID,
-                                  Operands, IsVarLenInst)) {
-        if (IsVarLenInst) {
-          MaxInstLen = std::max(MaxInstLen, Len);
-          InstrLen[EncodingID] = Len;
-        }
-        StringRef DecoderNamespace =
-            EncodingDef->getValueAsString("DecoderNamespace");
-        EncMap[{DecoderNamespace, HwModeID, Size}].push_back(EncodingID);
-      } else {
-        NumEncodingsOmitted++;
-      }
+      StringRef DecoderNamespace =
+          EncodingDef->getValueAsString("DecoderNamespace");
+      EncMap[{DecoderNamespace, HwModeID, Size}].push_back(EncodingID);
     }
   }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/154309


More information about the llvm-commits mailing list