[llvm] [TableGen][DecoderEmitter] Rework table construction/emission (PR #155889)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 17 11:54:11 PDT 2025


================
@@ -1718,6 +1245,619 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
 )";
 }
 
+namespace {
+
+class DecoderTreeNode {
+public:
+  virtual ~DecoderTreeNode() = default;
+
+  enum KindTy {
+    CheckAny,
+    CheckAll,
+    CheckField,
+    SwitchField,
+    CheckPredicate,
+    SoftFail,
+    Decode,
+  };
+
+  KindTy getKind() const { return Kind; }
+
+protected:
+  explicit DecoderTreeNode(KindTy Kind) : Kind(Kind) {}
+
+private:
+  KindTy Kind;
+};
+
+class CheckAnyNode : public DecoderTreeNode {
+  SmallVector<std::unique_ptr<DecoderTreeNode>, 0> Children;
+
+  static const DecoderTreeNode *
+  mapElement(decltype(Children)::const_reference Element) {
+    return Element.get();
+  }
+
+public:
+  CheckAnyNode() : DecoderTreeNode(CheckAny) {}
+
+  void addChild(std::unique_ptr<DecoderTreeNode> N) {
+    Children.push_back(std::move(N));
+  }
+
+  using child_iterator = mapped_iterator<decltype(Children)::const_iterator,
+                                         decltype(&mapElement)>;
+
+  child_iterator child_begin() const {
+    return child_iterator(Children.begin(), mapElement);
+  }
+
+  child_iterator child_end() const {
+    return child_iterator(Children.end(), mapElement);
+  }
+
+  iterator_range<child_iterator> children() const {
+    return make_range(child_begin(), child_end());
+  }
+};
+
+class CheckAllNode : public DecoderTreeNode {
+  SmallVector<std::unique_ptr<DecoderTreeNode>, 0> Children;
+
+  static const DecoderTreeNode *
+  mapElement(decltype(Children)::const_reference Element) {
+    return Element.get();
+  }
+
+public:
+  CheckAllNode() : DecoderTreeNode(CheckAll) {}
+
+  void addChild(std::unique_ptr<DecoderTreeNode> Child) {
+    Children.push_back(std::move(Child));
+  }
+
+  using child_iterator = mapped_iterator<decltype(Children)::const_iterator,
+                                         decltype(&mapElement)>;
+
+  child_iterator child_begin() const {
+    return child_iterator(Children.begin(), mapElement);
+  }
+
+  child_iterator child_end() const {
+    return child_iterator(Children.end(), mapElement);
+  }
+
+  iterator_range<child_iterator> children() const {
+    return make_range(child_begin(), child_end());
+  }
+};
+
+class CheckFieldNode : public DecoderTreeNode {
+  unsigned StartBit;
+  unsigned NumBits;
+  uint64_t Value;
+
+public:
+  CheckFieldNode(unsigned StartBit, unsigned NumBits, uint64_t Value)
+      : DecoderTreeNode(CheckField), StartBit(StartBit), NumBits(NumBits),
+        Value(Value) {}
+
+  unsigned getStartBit() const { return StartBit; }
+
+  unsigned getNumBits() const { return NumBits; }
+
+  uint64_t getValue() const { return Value; }
+};
+
+class SwitchFieldNode : public DecoderTreeNode {
+  unsigned StartBit;
+  unsigned NumBits;
+  std::map<uint64_t, std::unique_ptr<DecoderTreeNode>> Cases;
+
+  static std::pair<uint64_t, const DecoderTreeNode *>
+  mapElement(decltype(Cases)::const_reference Element) {
+    return std::pair(Element.first, Element.second.get());
+  }
+
+public:
+  SwitchFieldNode(unsigned StartBit, unsigned NumBits)
+      : DecoderTreeNode(SwitchField), StartBit(StartBit), NumBits(NumBits) {}
+
+  void addCase(uint64_t Value, std::unique_ptr<DecoderTreeNode> N) {
+    Cases.try_emplace(Value, std::move(N));
+  }
+
+  unsigned getStartBit() const { return StartBit; }
+
+  unsigned getNumBits() const { return NumBits; }
+
+  using case_iterator =
+      mapped_iterator<decltype(Cases)::const_iterator, decltype(&mapElement)>;
+
+  case_iterator case_begin() const {
+    return case_iterator(Cases.begin(), mapElement);
+  }
+
+  case_iterator case_end() const {
+    return case_iterator(Cases.end(), mapElement);
+  }
+
+  iterator_range<case_iterator> cases() const {
+    return make_range(case_begin(), case_end());
+  }
+};
+
+class CheckPredicateNode : public DecoderTreeNode {
+  std::string PredicateString;
+
+public:
+  explicit CheckPredicateNode(std::string PredicateString)
+      : DecoderTreeNode(CheckPredicate),
+        PredicateString(std::move(PredicateString)) {}
+
+  StringRef getPredicateString() const { return PredicateString; }
+};
+
+class SoftFailNode : public DecoderTreeNode {
+  uint64_t PositiveMask, NegativeMask;
+
+public:
+  SoftFailNode(uint64_t PositiveMask, uint64_t NegativeMask)
+      : DecoderTreeNode(SoftFail), PositiveMask(PositiveMask),
+        NegativeMask(NegativeMask) {}
+
+  uint64_t getPositiveMask() const { return PositiveMask; }
+  uint64_t getNegativeMask() const { return NegativeMask; }
+};
+
+class DecodeNode : public DecoderTreeNode {
+  const InstructionEncoding &Encoding;
+  std::string DecoderString;
+
+public:
+  DecodeNode(const InstructionEncoding &Encoding, std::string DecoderString)
+      : DecoderTreeNode(Decode), Encoding(Encoding),
+        DecoderString(std::move(DecoderString)) {}
+
+  const InstructionEncoding &getEncoding() const { return Encoding; }
+
+  StringRef getDecoderString() const { return DecoderString; }
+};
+
+class DecoderTreeBuilder {
+  const CodeGenTarget &Target;
+  ArrayRef<InstructionEncoding> Encodings;
+
+public:
+  DecoderTreeBuilder(const CodeGenTarget &Target,
+                     ArrayRef<InstructionEncoding> Encodings)
+      : Target(Target), Encodings(Encodings) {}
+
+  std::unique_ptr<DecoderTreeNode> buildTree(const FilterChooser &FC) {
+    return buildCheckAnyNode(FC);
+  }
+
+private:
+  std::unique_ptr<DecoderTreeNode>
+  buildTerminalNode(unsigned EncodingID, const KnownBits &FilterBits);
+
+  std::unique_ptr<DecoderTreeNode> buildCheckAllOrSwitchNode(
+      unsigned StartBit, unsigned NumBits,
+      const std::map<uint64_t, std::unique_ptr<const FilterChooser>> &FCMap);
+
+  std::unique_ptr<DecoderTreeNode> buildCheckAnyNode(const FilterChooser &FC);
+};
+
+class DecoderTableEmitter {
+  DecoderTableInfo &TableInfo;
+  formatted_raw_ostream OS;
+  unsigned IndexWidth;
+  unsigned CurrentIndex;
+  unsigned CommentIndex;
+
+public:
+  DecoderTableEmitter(DecoderTableInfo &TableInfo, raw_ostream &OS)
+      : TableInfo(TableInfo), OS(OS) {}
+
+  void emitTable(StringRef TableName, unsigned BitWidth,
+                 const DecoderTreeNode *Root);
+
+private:
+  void analyzeNode(const DecoderTreeNode *Node) const;
+
+  unsigned computeNodeSize(const DecoderTreeNode *Node) const;
+  unsigned computeTableSize(const DecoderTreeNode *Root,
+                            unsigned BitWidth) const;
+
+  void emitStartLine();
+  void emitOpcode(StringRef Name);
+  void emitByte(uint8_t Val);
+  void emitUInt8(unsigned Val);
+  void emitULEB128(uint64_t Val);
+  formatted_raw_ostream &emitComment(indent Indent);
+
+  void emitCheckAnyNode(const CheckAnyNode *N, indent Indent);
+  void emitCheckAllNode(const CheckAllNode *N, indent Indent);
+  void emitSwitchFieldNode(const SwitchFieldNode *N, indent Indent);
+  void emitCheckFieldNode(const CheckFieldNode *N, indent Indent);
+  void emitCheckPredicateNode(const CheckPredicateNode *N, indent Indent);
+  void emitSoftFailNode(const SoftFailNode *N, indent Indent);
+  void emitDecodeNode(const DecodeNode *N, indent Indent);
+  void emitNode(const DecoderTreeNode *N, indent Indent);
+};
+
+} // namespace
+
+std::unique_ptr<DecoderTreeNode>
+DecoderTreeBuilder::buildTerminalNode(unsigned EncodingID,
+                                      const KnownBits &FilterBits) {
+  const InstructionEncoding &Encoding = Encodings[EncodingID];
+  auto N = std::make_unique<CheckAllNode>();
+
+  std::string Predicate = getPredicateString(Encoding, Target.getName());
+  if (!Predicate.empty())
+    N->addChild(std::make_unique<CheckPredicateNode>(std::move(Predicate)));
+
+  std::vector<FilterChooser::Island> Islands =
+      FilterChooser::getIslands(Encoding.getMandatoryBits(), FilterBits);
+  for (const FilterChooser::Island &Ilnd : reverse(Islands)) {
+    N->addChild(std::make_unique<CheckFieldNode>(Ilnd.StartBit, Ilnd.NumBits,
+                                                 Ilnd.FieldVal));
+  }
+
+  const KnownBits &InstBits = Encoding.getInstBits();
+  const APInt &SoftFailMask = Encoding.getSoftFailMask();
+  if (!SoftFailMask.isZero()) {
+    APInt PositiveMask = InstBits.Zero & SoftFailMask;
+    APInt NegativeMask = InstBits.One & SoftFailMask;
+    N->addChild(std::make_unique<SoftFailNode>(PositiveMask.getZExtValue(),
+                                               NegativeMask.getZExtValue()));
+  }
+
+  std::string DecoderIndex = getDecoderString(Encoding);
+  N->addChild(std::make_unique<DecodeNode>(Encoding, DecoderIndex));
+
+  return N;
+}
+
+std::unique_ptr<DecoderTreeNode> DecoderTreeBuilder::buildCheckAllOrSwitchNode(
+    unsigned StartBit, unsigned NumBits,
+    const std::map<uint64_t, std::unique_ptr<const FilterChooser>> &FCMap) {
+  if (FCMap.size() == 1) {
+    const auto &[FieldVal, ChildFC] = *FCMap.begin();
+    auto N = std::make_unique<CheckAllNode>();
+    N->addChild(std::make_unique<CheckFieldNode>(StartBit, NumBits, FieldVal));
+    N->addChild(buildCheckAnyNode(*ChildFC));
+    return N;
+  }
+  auto N = std::make_unique<SwitchFieldNode>(StartBit, NumBits);
+  for (const auto &[FieldVal, ChildFC] : FCMap)
+    N->addCase(FieldVal, buildCheckAnyNode(*ChildFC));
+  return N;
+}
+
+std::unique_ptr<DecoderTreeNode>
+DecoderTreeBuilder::buildCheckAnyNode(const FilterChooser &FC) {
+  auto N = std::make_unique<CheckAnyNode>();
+  if (FC.SingletonEncodingID) {
+    N->addChild(buildTerminalNode(*FC.SingletonEncodingID, FC.FilterBits));
+  } else {
+    N->addChild(buildCheckAllOrSwitchNode(FC.StartBit, FC.NumBits,
+                                          FC.FilterChooserMap));
+  }
+  if (FC.VariableFC) {
----------------
jurahul wrote:

nit: CS no {}

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


More information about the llvm-commits mailing list