[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