//===----------------------------------------------------------------------===// // // 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 #include namespace llvm { class InstructionEncoding; using PredicateSet = SetVector; using DecoderSet = SetVector; /// 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, 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 Child) { Children.push_back(std::move(Child)); } using child_iterator = mapped_iterator; child_iterator child_begin() const { return child_iterator(Children.begin(), mapElement); } child_iterator child_end() const { return child_iterator(Children.end(), mapElement); } iterator_range 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> Cases; static std::pair 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 N) { Cases.try_emplace(Value, std::move(N)); } unsigned getStartBit() const { return StartBit; } unsigned getNumBits() const { return NumBits; } using case_iterator = mapped_iterator; case_iterator case_begin() const { return case_iterator(Cases.begin(), mapElement); } case_iterator case_end() const { return case_iterator(Cases.end(), mapElement); } iterator_range 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