| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_UTILS_TABLEGEN_DECODERTREE_H | |
| #define LLVM_UTILS_TABLEGEN_DECODERTREE_H | |
| #include "llvm/ADT/CachedHashString.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/SetVector.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include <map> | |
| #include <memory> | |
| namespace llvm { | |
| class InstructionEncoding; | |
| using PredicateSet = SetVector<CachedHashString>; | |
| using DecoderSet = SetVector<CachedHashString>; | |
| /// Context shared across decoder trees. | |
| /// Predicates and decoders are shared across decoder trees to provide more | |
| /// opportunities for uniqueness. If SpecializeDecodersPerBitwidth is enabled, | |
| /// decoders are shared across all trees for a given bitwidth, else they are | |
| /// shared across all trees. Predicates are always shared across all trees. | |
| struct DecoderContext { | |
| PredicateSet Predicates; | |
| DecoderSet Decoders; | |
| unsigned getPredicateIndex(StringRef Predicate) { | |
| Predicates.insert(CachedHashString(Predicate)); | |
| PredicateSet::const_iterator I = find(Predicates, Predicate); | |
| return std::distance(Predicates.begin(), I); | |
| } | |
| unsigned getDecoderIndex(StringRef Decoder) { | |
| Decoders.insert(CachedHashString(Decoder)); | |
| DecoderSet::const_iterator I = find(Decoders, Decoder); | |
| return std::distance(Decoders.begin(), I); | |
| } | |
| }; | |
| class DecoderTreeNode { | |
| public: | |
| virtual ~DecoderTreeNode(); | |
| enum KindTy { | |
| CheckAny, | |
| CheckAll, | |
| CheckField, | |
| SwitchField, | |
| CheckPredicate, | |
| SoftFail, | |
| Decode, | |
| }; | |
| KindTy getKind() const { return Kind; } | |
| protected: | |
| explicit DecoderTreeNode(KindTy Kind) : Kind(Kind) {} | |
| private: | |
| KindTy Kind; | |
| }; | |
| /// Common base class for nodes with multiple children. | |
| class CheckManyNode : public DecoderTreeNode { | |
| SmallVector<std::unique_ptr<DecoderTreeNode>, 0> Children; | |
| static const DecoderTreeNode * | |
| mapElement(decltype(Children)::const_reference Element) { | |
| return Element.get(); | |
| } | |
| protected: | |
| explicit CheckManyNode(KindTy Kind) : DecoderTreeNode(Kind) {} | |
| public: | |
| 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()); | |
| } | |
| }; | |
| /// Executes child nodes one by one until one of them succeeds or all fail. | |
| /// The node fails if all child nodes fail. It never succeeds, because if a | |
| /// child node succeeds, it does not return. | |
| class CheckAnyNode : public CheckManyNode { | |
| public: | |
| CheckAnyNode() : CheckManyNode(CheckAny) {} | |
| }; | |
| /// Executes child nodes one by one until one of them fails all all succeed. | |
| /// The node fails if any of the child nodes fails. | |
| class CheckAllNode : public CheckManyNode { | |
| public: | |
| CheckAllNode() : CheckManyNode(CheckAll) {} | |
| }; | |
| /// Checks the value of encoding bits in the specified range. | |
| 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; } | |
| }; | |
| /// Switch based on the value of encoding bits in the specified range. | |
| /// If the value of the bits in the range doesn't match any of the cases, | |
| /// the node fails. This is semantically equivalent to CheckAny node where | |
| /// every child is a CheckField node, but is faster. | |
| 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()); | |
| } | |
| }; | |
| /// Checks that the instruction to be decoded has its predicates satisfied. | |
| class CheckPredicateNode : public DecoderTreeNode { | |
| unsigned PredicateIndex; | |
| public: | |
| explicit CheckPredicateNode(unsigned PredicateIndex) | |
| : DecoderTreeNode(CheckPredicate), PredicateIndex(PredicateIndex) {} | |
| unsigned getPredicateIndex() const { return PredicateIndex; } | |
| }; | |
| /// Checks if the encoding bits are correct w.r.t. SoftFail semantics. | |
| /// This is the only node that can never fail. | |
| 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; } | |
| }; | |
| /// Attempts to decode the specified encoding as the specified instruction. | |
| class DecodeNode : public DecoderTreeNode { | |
| StringRef EncodingName; | |
| unsigned InstOpcode; | |
| unsigned DecoderIndex; | |
| public: | |
| DecodeNode(StringRef EncodingName, unsigned InstOpcode, unsigned DecoderIndex) | |
| : DecoderTreeNode(Decode), EncodingName(EncodingName), | |
| InstOpcode(InstOpcode), DecoderIndex(DecoderIndex) {} | |
| StringRef getEncodingName() const { return EncodingName; } | |
| unsigned getInstOpcode() const { return InstOpcode; } | |
| unsigned getDecoderIndex() const { return DecoderIndex; } | |
| }; | |
| } // namespace llvm | |
| #endif // LLVM_UTILS_TABLEGEN_DECODERTREE_H |