//===- CodeGenDAGPatterns.h - Read DAG patterns from .td file ---*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // // This file declares the CodeGenDAGPatterns class, which is used to read and // represent the patterns present in a .td file for instructions. // //===----------------------------------------------------------------------===// #ifndef LLVM_UTILS_TABLEGEN_CODEGENDAGPATTERNS_H #define LLVM_UTILS_TABLEGEN_CODEGENDAGPATTERNS_H #include "Basic/CodeGenIntrinsics.h" #include "Basic/SDNodeProperties.h" #include "CodeGenTarget.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/TableGen/Record.h" #include #include #include #include #include #include namespace llvm { class Init; class ListInit; class DagInit; class SDNodeInfo; class TreePattern; class TreePatternNode; class CodeGenDAGPatterns; /// Shared pointer for TreePatternNode. using TreePatternNodePtr = IntrusiveRefCntPtr; /// This represents a set of MVTs. Since the underlying type for the MVT /// is uint8_t, there are at most 256 values. To reduce the number of memory /// allocations and deallocations, represent the set as a sequence of bits. /// To reduce the allocations even further, make MachineValueTypeSet own /// the storage and use std::array as the bit container. struct MachineValueTypeSet { static_assert(std::is_same, uint8_t>::value, "Change uint8_t here to the SimpleValueType's type"); static unsigned constexpr Capacity = std::numeric_limits::max() + 1; using WordType = uint64_t; static unsigned constexpr WordWidth = CHAR_BIT * sizeof(WordType); static unsigned constexpr NumWords = Capacity / WordWidth; static_assert(NumWords * WordWidth == Capacity, "Capacity should be a multiple of WordWidth"); LLVM_ATTRIBUTE_ALWAYS_INLINE MachineValueTypeSet() { clear(); } LLVM_ATTRIBUTE_ALWAYS_INLINE unsigned size() const { unsigned Count = 0; for (WordType W : Words) Count += llvm::popcount(W); return Count; } LLVM_ATTRIBUTE_ALWAYS_INLINE void clear() { std::memset(Words.data(), 0, NumWords * sizeof(WordType)); } LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const { for (WordType W : Words) if (W != 0) return false; return true; } LLVM_ATTRIBUTE_ALWAYS_INLINE unsigned count(MVT T) const { return (Words[T.SimpleTy / WordWidth] >> (T.SimpleTy % WordWidth)) & 1; } std::pair insert(MVT T) { bool V = count(T.SimpleTy); Words[T.SimpleTy / WordWidth] |= WordType(1) << (T.SimpleTy % WordWidth); return {*this, V}; } MachineValueTypeSet &insert(const MachineValueTypeSet &S) { for (unsigned i = 0; i != NumWords; ++i) Words[i] |= S.Words[i]; return *this; } LLVM_ATTRIBUTE_ALWAYS_INLINE void erase(MVT T) { Words[T.SimpleTy / WordWidth] &= ~(WordType(1) << (T.SimpleTy % WordWidth)); } void writeToStream(raw_ostream &OS) const; struct const_iterator { // Some implementations of the C++ library require these traits to be // defined. using iterator_category = std::forward_iterator_tag; using value_type = MVT; using difference_type = ptrdiff_t; using pointer = const MVT *; using reference = const MVT &; LLVM_ATTRIBUTE_ALWAYS_INLINE MVT operator*() const { assert(Pos != Capacity); return MVT::SimpleValueType(Pos); } LLVM_ATTRIBUTE_ALWAYS_INLINE const_iterator(const MachineValueTypeSet *S, bool End) : Set(S) { Pos = End ? Capacity : find_from_pos(0); } LLVM_ATTRIBUTE_ALWAYS_INLINE const_iterator &operator++() { assert(Pos != Capacity); Pos = find_from_pos(Pos + 1); return *this; } LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator==(const const_iterator &It) const { return Set == It.Set && Pos == It.Pos; } LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator!=(const const_iterator &It) const { return !operator==(It); } private: unsigned find_from_pos(unsigned P) const { unsigned SkipWords = P / WordWidth; unsigned SkipBits = P % WordWidth; unsigned Count = SkipWords * WordWidth; // If P is in the middle of a word, process it manually here, because // the trailing bits need to be masked off to use findFirstSet. if (SkipBits != 0) { WordType W = Set->Words[SkipWords]; W &= maskLeadingOnes(WordWidth - SkipBits); if (W != 0) return Count + llvm::countr_zero(W); Count += WordWidth; SkipWords++; } for (unsigned i = SkipWords; i != NumWords; ++i) { WordType W = Set->Words[i]; if (W != 0) return Count + llvm::countr_zero(W); Count += WordWidth; } return Capacity; } const MachineValueTypeSet *Set; unsigned Pos; }; LLVM_ATTRIBUTE_ALWAYS_INLINE const_iterator begin() const { return const_iterator(this, false); } LLVM_ATTRIBUTE_ALWAYS_INLINE const_iterator end() const { return const_iterator(this, true); } LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator==(const MachineValueTypeSet &S) const { return Words == S.Words; } LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator!=(const MachineValueTypeSet &S) const { return !operator==(S); } private: friend struct const_iterator; std::array Words; }; raw_ostream &operator<<(raw_ostream &OS, const MachineValueTypeSet &T); struct TypeSetByHwMode : public InfoByHwMode { using SetType = MachineValueTypeSet; unsigned AddrSpace = std::numeric_limits::max(); TypeSetByHwMode() = default; TypeSetByHwMode(const TypeSetByHwMode &VTS) = default; TypeSetByHwMode &operator=(const TypeSetByHwMode &) = default; TypeSetByHwMode(MVT::SimpleValueType VT) : TypeSetByHwMode(ValueTypeByHwMode(VT)) {} TypeSetByHwMode(ValueTypeByHwMode VT) : TypeSetByHwMode(ArrayRef(&VT, 1)) {} TypeSetByHwMode(ArrayRef VTList); SetType &getOrCreate(unsigned Mode) { return Map[Mode]; } bool isValueTypeByHwMode(bool AllowEmpty) const; ValueTypeByHwMode getValueTypeByHwMode() const; LLVM_ATTRIBUTE_ALWAYS_INLINE bool isMachineValueType() const { return isSimple() && getSimple().size() == 1; } LLVM_ATTRIBUTE_ALWAYS_INLINE MVT getMachineValueType() const { assert(isMachineValueType()); return *getSimple().begin(); } bool isPossible() const; bool isPointer() const { return getValueTypeByHwMode().isPointer(); } unsigned getPtrAddrSpace() const { assert(isPointer()); return getValueTypeByHwMode().PtrAddrSpace; } bool insert(const ValueTypeByHwMode &VVT); bool constrain(const TypeSetByHwMode &VTS); template bool constrain(Predicate P); template bool assign_if(const TypeSetByHwMode &VTS, Predicate P); void writeToStream(raw_ostream &OS) const; bool operator==(const TypeSetByHwMode &VTS) const; bool operator!=(const TypeSetByHwMode &VTS) const { return !(*this == VTS); } void dump() const; bool validate() const; private: unsigned PtrAddrSpace = std::numeric_limits::max(); /// Intersect two sets. Return true if anything has changed. bool intersect(SetType &Out, const SetType &In); }; raw_ostream &operator<<(raw_ostream &OS, const TypeSetByHwMode &T); struct TypeInfer { TypeInfer(TreePattern &T) : TP(T) {} bool isConcrete(const TypeSetByHwMode &VTS, bool AllowEmpty) const { return VTS.isValueTypeByHwMode(AllowEmpty); } ValueTypeByHwMode getConcrete(const TypeSetByHwMode &VTS, bool AllowEmpty) const { assert(VTS.isValueTypeByHwMode(AllowEmpty)); return VTS.getValueTypeByHwMode(); } /// The protocol in the following functions (Merge*, force*, Enforce*, /// expand*) is to return "true" if a change has been made, "false" /// otherwise. bool MergeInTypeInfo(TypeSetByHwMode &Out, const TypeSetByHwMode &In) const; bool MergeInTypeInfo(TypeSetByHwMode &Out, MVT::SimpleValueType InVT) const { return MergeInTypeInfo(Out, TypeSetByHwMode(InVT)); } bool MergeInTypeInfo(TypeSetByHwMode &Out, ValueTypeByHwMode InVT) const { return MergeInTypeInfo(Out, TypeSetByHwMode(InVT)); } /// Reduce the set \p Out to have at most one element for each mode. bool forceArbitrary(TypeSetByHwMode &Out); /// The following four functions ensure that upon return the set \p Out /// will only contain types of the specified kind: integer, floating-point, /// scalar, or vector. /// If \p Out is empty, all legal types of the specified kind will be added /// to it. Otherwise, all types that are not of the specified kind will be /// removed from \p Out. bool EnforceInteger(TypeSetByHwMode &Out); bool EnforceFloatingPoint(TypeSetByHwMode &Out); bool EnforceScalar(TypeSetByHwMode &Out); bool EnforceVector(TypeSetByHwMode &Out); /// If \p Out is empty, fill it with all legal types. Otherwise, leave it /// unchanged. bool EnforceAny(TypeSetByHwMode &Out); /// Make sure that for each type in \p Small, there exists a larger type /// in \p Big. \p SmallIsVT indicates that this is being called for /// SDTCisVTSmallerThanOp. In that case the TypeSetByHwMode is re-created for /// each call and needs special consideration in how we detect changes. bool EnforceSmallerThan(TypeSetByHwMode &Small, TypeSetByHwMode &Big, bool SmallIsVT = false); /// 1. Ensure that for each type T in \p Vec, T is a vector type, and that /// for each type U in \p Elem, U is a scalar type. /// 2. Ensure that for each (scalar) type U in \p Elem, there exists a /// (vector) type T in \p Vec, such that U is the element type of T. bool EnforceVectorEltTypeIs(TypeSetByHwMode &Vec, TypeSetByHwMode &Elem); bool EnforceVectorEltTypeIs(TypeSetByHwMode &Vec, const ValueTypeByHwMode &VVT); /// Ensure that for each type T in \p Sub, T is a vector type, and there /// exists a type U in \p Vec such that U is a vector type with the same /// element type as T and at least as many elements as T. bool EnforceVectorSubVectorTypeIs(TypeSetByHwMode &Vec, TypeSetByHwMode &Sub); /// 1. Ensure that \p V has a scalar type iff \p W has a scalar type. /// 2. Ensure that for each vector type T in \p V, there exists a vector /// type U in \p W, such that T and U have the same number of elements. /// 3. Ensure that for each vector type U in \p W, there exists a vector /// type T in \p V, such that T and U have the same number of elements /// (reverse of 2). bool EnforceSameNumElts(TypeSetByHwMode &V, TypeSetByHwMode &W); /// 1. Ensure that for each type T in \p A, there exists a type U in \p B, /// such that T and U have equal size in bits. /// 2. Ensure that for each type U in \p B, there exists a type T in \p A /// such that T and U have equal size in bits (reverse of 1). bool EnforceSameSize(TypeSetByHwMode &A, TypeSetByHwMode &B); /// For each overloaded type (i.e. of form *Any), replace it with the /// corresponding subset of legal, specific types. void expandOverloads(TypeSetByHwMode &VTS) const; void expandOverloads(TypeSetByHwMode::SetType &Out, const TypeSetByHwMode::SetType &Legal) const; struct ValidateOnExit { ValidateOnExit(const TypeSetByHwMode &T, const TypeInfer &TI) : Infer(TI), VTS(T) {} ~ValidateOnExit(); const TypeInfer &Infer; const TypeSetByHwMode &VTS; }; struct SuppressValidation { SuppressValidation(TypeInfer &TI) : Infer(TI), SavedValidate(TI.Validate) { Infer.Validate = false; } ~SuppressValidation() { Infer.Validate = SavedValidate; } TypeInfer &Infer; bool SavedValidate; }; TreePattern &TP; bool Validate = true; // Indicate whether to validate types. private: const TypeSetByHwMode &getLegalTypes() const; /// Cached legal types (in default mode). mutable bool LegalTypesCached = false; mutable TypeSetByHwMode LegalCache; }; /// Set type used to track multiply used variables in patterns typedef StringSet<> MultipleUseVarSet; /// SDTypeConstraint - This is a discriminated union of constraints, /// corresponding to the SDTypeConstraint tablegen class in Target.td. struct SDTypeConstraint { SDTypeConstraint(Record *R, const CodeGenHwModes &CGH); unsigned OperandNo; // The operand # this constraint applies to. enum { SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs, SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec, SDTCisSubVecOfVec, SDTCVecEltisVT, SDTCisSameNumEltsAs, SDTCisSameSizeAs } ConstraintType; union { // The discriminated union. struct { unsigned OtherOperandNum; } SDTCisSameAs_Info; struct { unsigned OtherOperandNum; } SDTCisVTSmallerThanOp_Info; struct { unsigned BigOperandNum; } SDTCisOpSmallerThanOp_Info; struct { unsigned OtherOperandNum; } SDTCisEltOfVec_Info; struct { unsigned OtherOperandNum; } SDTCisSubVecOfVec_Info; struct { unsigned OtherOperandNum; } SDTCisSameNumEltsAs_Info; struct { unsigned OtherOperandNum; } SDTCisSameSizeAs_Info; } x; // The VT for SDTCisVT and SDTCVecEltisVT. // Must not be in the union because it has a non-trivial destructor. ValueTypeByHwMode VVT; /// ApplyTypeConstraint - Given a node in a pattern, apply this type /// constraint to the nodes operands. This returns true if it makes a /// change, false otherwise. If a type contradiction is found, an error /// is flagged. bool ApplyTypeConstraint(TreePatternNode &N, const SDNodeInfo &NodeInfo, TreePattern &TP) const; }; /// ScopedName - A name of a node associated with a "scope" that indicates /// the context (e.g. instance of Pattern or PatFrag) in which the name was /// used. This enables substitution of pattern fragments while keeping track /// of what name(s) were originally given to various nodes in the tree. class ScopedName { unsigned Scope; std::string Identifier; public: ScopedName(unsigned Scope, StringRef Identifier) : Scope(Scope), Identifier(std::string(Identifier)) { assert(Scope != 0 && "Scope == 0 is used to indicate predicates without arguments"); } unsigned getScope() const { return Scope; } const std::string &getIdentifier() const { return Identifier; } bool operator==(const ScopedName &o) const; bool operator!=(const ScopedName &o) const; }; /// SDNodeInfo - One of these records is created for each SDNode instance in /// the target .td file. This represents the various dag nodes we will be /// processing. class SDNodeInfo { Record *Def; StringRef EnumName; StringRef SDClassName; unsigned Properties; unsigned NumResults; int NumOperands; std::vector TypeConstraints; public: // Parse the specified record. SDNodeInfo(Record *R, const CodeGenHwModes &CGH); unsigned getNumResults() const { return NumResults; } /// getNumOperands - This is the number of operands required or -1 if /// variadic. int getNumOperands() const { return NumOperands; } Record *getRecord() const { return Def; } StringRef getEnumName() const { return EnumName; } StringRef getSDClassName() const { return SDClassName; } const std::vector &getTypeConstraints() const { return TypeConstraints; } /// getKnownType - If the type constraints on this node imply a fixed type /// (e.g. all stores return void, etc), then return it as an /// MVT::SimpleValueType. Otherwise, return MVT::Other. MVT::SimpleValueType getKnownType(unsigned ResNo) const; /// hasProperty - Return true if this node has the specified property. /// bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); } /// ApplyTypeConstraints - Given a node in a pattern, apply the type /// constraints for this node to the operands of the node. This returns /// true if it makes a change, false otherwise. If a type contradiction is /// found, an error is flagged. bool ApplyTypeConstraints(TreePatternNode &N, TreePattern &TP) const; }; /// TreePredicateFn - This is an abstraction that represents the predicates on /// a PatFrag node. This is a simple one-word wrapper around a pointer to /// provide nice accessors. class TreePredicateFn { /// PatFragRec - This is the TreePattern for the PatFrag that we /// originally came from. TreePattern *PatFragRec; public: /// TreePredicateFn constructor. Here 'N' is a subclass of PatFrag. TreePredicateFn(TreePattern *N); TreePattern *getOrigPatFragRecord() const { return PatFragRec; } /// isAlwaysTrue - Return true if this is a noop predicate. bool isAlwaysTrue() const; bool isImmediatePattern() const { return hasImmCode(); } /// getImmediatePredicateCode - Return the code that evaluates this pattern if /// this is an immediate predicate. It is an error to call this on a /// non-immediate pattern. std::string getImmediatePredicateCode() const { std::string Result = getImmCode(); assert(!Result.empty() && "Isn't an immediate pattern!"); return Result; } bool operator==(const TreePredicateFn &RHS) const { return PatFragRec == RHS.PatFragRec; } bool operator!=(const TreePredicateFn &RHS) const { return !(*this == RHS); } /// Return the name to use in the generated code to reference this, this is /// "Predicate_foo" if from a pattern fragment "foo". std::string getFnName() const; /// getCodeToRunOnSDNode - Return the code for the function body that /// evaluates this predicate. The argument is expected to be in "Node", /// not N. This handles casting and conversion to a concrete node type as /// appropriate. std::string getCodeToRunOnSDNode() const; /// Get the data type of the argument to getImmediatePredicateCode(). StringRef getImmType() const; /// Get a string that describes the type returned by getImmType() but is /// usable as part of an identifier. StringRef getImmTypeIdentifier() const; // Predicate code uses the PatFrag's captured operands. bool usesOperands() const; // Check if the HasNoUse predicate is set. bool hasNoUse() const; // Check if the HasOneUse predicate is set. bool hasOneUse() const; // Is the desired predefined predicate for a load? bool isLoad() const; // Is the desired predefined predicate for a store? bool isStore() const; // Is the desired predefined predicate for an atomic? bool isAtomic() const; /// Is this predicate the predefined unindexed load predicate? /// Is this predicate the predefined unindexed store predicate? bool isUnindexed() const; /// Is this predicate the predefined non-extending load predicate? bool isNonExtLoad() const; /// Is this predicate the predefined any-extend load predicate? bool isAnyExtLoad() const; /// Is this predicate the predefined sign-extend load predicate? bool isSignExtLoad() const; /// Is this predicate the predefined zero-extend load predicate? bool isZeroExtLoad() const; /// Is this predicate the predefined non-truncating store predicate? bool isNonTruncStore() const; /// Is this predicate the predefined truncating store predicate? bool isTruncStore() const; /// Is this predicate the predefined monotonic atomic predicate? bool isAtomicOrderingMonotonic() const; /// Is this predicate the predefined acquire atomic predicate? bool isAtomicOrderingAcquire() const; /// Is this predicate the predefined release atomic predicate? bool isAtomicOrderingRelease() const; /// Is this predicate the predefined acquire-release atomic predicate? bool isAtomicOrderingAcquireRelease() const; /// Is this predicate the predefined sequentially consistent atomic predicate? bool isAtomicOrderingSequentiallyConsistent() const; /// Is this predicate the predefined acquire-or-stronger atomic predicate? bool isAtomicOrderingAcquireOrStronger() const; /// Is this predicate the predefined weaker-than-acquire atomic predicate? bool isAtomicOrderingWeakerThanAcquire() const; /// Is this predicate the predefined release-or-stronger atomic predicate? bool isAtomicOrderingReleaseOrStronger() const; /// Is this predicate the predefined weaker-than-release atomic predicate? bool isAtomicOrderingWeakerThanRelease() const; /// If non-null, indicates that this predicate is a predefined memory VT /// predicate for a load/store and returns the ValueType record for the memory /// VT. Record *getMemoryVT() const; /// If non-null, indicates that this predicate is a predefined memory VT /// predicate (checking only the scalar type) for load/store and returns the /// ValueType record for the memory VT. Record *getScalarMemoryVT() const; ListInit *getAddressSpaces() const; int64_t getMinAlignment() const; // If true, indicates that GlobalISel-based C++ code was supplied. bool hasGISelPredicateCode() const; std::string getGISelPredicateCode() const; private: bool hasPredCode() const; bool hasImmCode() const; std::string getPredCode() const; std::string getImmCode() const; bool immCodeUsesAPInt() const; bool immCodeUsesAPFloat() const; bool isPredefinedPredicateEqualTo(StringRef Field, bool Value) const; }; struct TreePredicateCall { TreePredicateFn Fn; // Scope -- unique identifier for retrieving named arguments. 0 is used when // the predicate does not use named arguments. unsigned Scope; TreePredicateCall(const TreePredicateFn &Fn, unsigned Scope) : Fn(Fn), Scope(Scope) {} bool operator==(const TreePredicateCall &o) const { return Fn == o.Fn && Scope == o.Scope; } bool operator!=(const TreePredicateCall &o) const { return !(*this == o); } }; class TreePatternNode : public RefCountedBase { /// The type of each node result. Before and during type inference, each /// result may be a set of possible types. After (successful) type inference, /// each is a single concrete type. std::vector Types; /// The index of each result in results of the pattern. std::vector ResultPerm; /// OperatorOrVal - The Record for the operator if this is an interior node /// (not a leaf) or the init value (e.g. the "GPRC" record, or "7") for a /// leaf. PointerUnion OperatorOrVal; /// Name - The name given to this node with the :$foo notation. /// std::string Name; std::vector NamesAsPredicateArg; /// PredicateCalls - The predicate functions to execute on this node to check /// for a match. If this list is empty, no predicate is involved. std::vector PredicateCalls; /// TransformFn - The transformation function to execute on this node before /// it can be substituted into the resulting instruction on a pattern match. Record *TransformFn; std::vector Children; /// If this was instantiated from a PatFrag node, and the PatFrag was derived /// from "GISelFlags": the original Record derived from GISelFlags. const Record *GISelFlags = nullptr; public: TreePatternNode(Record *Op, std::vector Ch, unsigned NumResults) : OperatorOrVal(Op), TransformFn(nullptr), Children(std::move(Ch)) { Types.resize(NumResults); ResultPerm.resize(NumResults); std::iota(ResultPerm.begin(), ResultPerm.end(), 0); } TreePatternNode(Init *val, unsigned NumResults) // leaf ctor : OperatorOrVal(val), TransformFn(nullptr) { Types.resize(NumResults); ResultPerm.resize(NumResults); std::iota(ResultPerm.begin(), ResultPerm.end(), 0); } bool hasName() const { return !Name.empty(); } const std::string &getName() const { return Name; } void setName(StringRef N) { Name.assign(N.begin(), N.end()); } const std::vector &getNamesAsPredicateArg() const { return NamesAsPredicateArg; } void setNamesAsPredicateArg(const std::vector &Names) { NamesAsPredicateArg = Names; } void addNameAsPredicateArg(const ScopedName &N) { NamesAsPredicateArg.push_back(N); } bool isLeaf() const { return isa(OperatorOrVal); } // Type accessors. unsigned getNumTypes() const { return Types.size(); } ValueTypeByHwMode getType(unsigned ResNo) const { return Types[ResNo].getValueTypeByHwMode(); } const std::vector &getExtTypes() const { return Types; } const TypeSetByHwMode &getExtType(unsigned ResNo) const { return Types[ResNo]; } TypeSetByHwMode &getExtType(unsigned ResNo) { return Types[ResNo]; } void setType(unsigned ResNo, const TypeSetByHwMode &T) { Types[ResNo] = T; } MVT::SimpleValueType getSimpleType(unsigned ResNo) const { return Types[ResNo].getMachineValueType().SimpleTy; } bool hasConcreteType(unsigned ResNo) const { return Types[ResNo].isValueTypeByHwMode(false); } bool isTypeCompletelyUnknown(unsigned ResNo, TreePattern &TP) const { return Types[ResNo].empty(); } unsigned getNumResults() const { return ResultPerm.size(); } unsigned getResultIndex(unsigned ResNo) const { return ResultPerm[ResNo]; } void setResultIndex(unsigned ResNo, unsigned RI) { ResultPerm[ResNo] = RI; } Init *getLeafValue() const { assert(isLeaf()); return cast(OperatorOrVal); } Record *getOperator() const { assert(!isLeaf()); return cast(OperatorOrVal); } unsigned getNumChildren() const { return Children.size(); } const TreePatternNode &getChild(unsigned N) const { return *Children[N].get(); } TreePatternNode &getChild(unsigned N) { return *Children[N].get(); } const TreePatternNodePtr &getChildShared(unsigned N) const { return Children[N]; } TreePatternNodePtr &getChildSharedPtr(unsigned N) { return Children[N]; } void setChild(unsigned i, TreePatternNodePtr N) { Children[i] = N; } /// hasChild - Return true if N is any of our children. bool hasChild(const TreePatternNode *N) const { for (unsigned i = 0, e = Children.size(); i != e; ++i) if (Children[i].get() == N) return true; return false; } bool hasProperTypeByHwMode() const; bool hasPossibleType() const; bool setDefaultMode(unsigned Mode); bool hasAnyPredicate() const { return !PredicateCalls.empty(); } const std::vector &getPredicateCalls() const { return PredicateCalls; } void clearPredicateCalls() { PredicateCalls.clear(); } void setPredicateCalls(const std::vector &Calls) { assert(PredicateCalls.empty() && "Overwriting non-empty predicate list!"); PredicateCalls = Calls; } void addPredicateCall(const TreePredicateCall &Call) { assert(!Call.Fn.isAlwaysTrue() && "Empty predicate string!"); assert(!is_contained(PredicateCalls, Call) && "predicate applied recursively"); PredicateCalls.push_back(Call); } void addPredicateCall(const TreePredicateFn &Fn, unsigned Scope) { assert((Scope != 0) == Fn.usesOperands()); addPredicateCall(TreePredicateCall(Fn, Scope)); } Record *getTransformFn() const { return TransformFn; } void setTransformFn(Record *Fn) { TransformFn = Fn; } /// getIntrinsicInfo - If this node corresponds to an intrinsic, return the /// CodeGenIntrinsic information for it, otherwise return a null pointer. const CodeGenIntrinsic *getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const; /// getComplexPatternInfo - If this node corresponds to a ComplexPattern, /// return the ComplexPattern information, otherwise return null. const ComplexPattern * getComplexPatternInfo(const CodeGenDAGPatterns &CGP) const; /// Returns the number of MachineInstr operands that would be produced by this /// node if it mapped directly to an output Instruction's /// operand. ComplexPattern specifies this explicitly; MIOperandInfo gives it /// for Operands; otherwise 1. unsigned getNumMIResults(const CodeGenDAGPatterns &CGP) const; /// NodeHasProperty - Return true if this node has the specified property. bool NodeHasProperty(SDNP Property, const CodeGenDAGPatterns &CGP) const; /// TreeHasProperty - Return true if any node in this tree has the specified /// property. bool TreeHasProperty(SDNP Property, const CodeGenDAGPatterns &CGP) const; /// isCommutativeIntrinsic - Return true if the node is an intrinsic which is /// marked isCommutative. bool isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const; void setGISelFlagsRecord(const Record *R) { GISelFlags = R; } const Record *getGISelFlagsRecord() const { return GISelFlags; } void print(raw_ostream &OS) const; void dump() const; public: // Higher level manipulation routines. /// clone - Return a new copy of this tree. /// TreePatternNodePtr clone() const; /// RemoveAllTypes - Recursively strip all the types of this tree. void RemoveAllTypes(); /// isIsomorphicTo - Return true if this node is recursively isomorphic to /// the specified node. For this comparison, all of the state of the node /// is considered, except for the assigned name. Nodes with differing names /// that are otherwise identical are considered isomorphic. bool isIsomorphicTo(const TreePatternNode &N, const MultipleUseVarSet &DepVars) const; /// SubstituteFormalArguments - Replace the formal arguments in this tree /// with actual values specified by ArgMap. void SubstituteFormalArguments(std::map &ArgMap); /// InlinePatternFragments - If \p T pattern refers to any pattern /// fragments, return the set of inlined versions (this can be more than /// one if a PatFrags record has multiple alternatives). void InlinePatternFragments(TreePattern &TP, std::vector &OutAlternatives); /// ApplyTypeConstraints - Apply all of the type constraints relevant to /// this node and its children in the tree. This returns true if it makes a /// change, false otherwise. If a type contradiction is found, flag an error. bool ApplyTypeConstraints(TreePattern &TP, bool NotRegisters); /// UpdateNodeType - Set the node type of N to VT if VT contains /// information. If N already contains a conflicting type, then flag an /// error. This returns true if any information was updated. /// bool UpdateNodeType(unsigned ResNo, const TypeSetByHwMode &InTy, TreePattern &TP); bool UpdateNodeType(unsigned ResNo, MVT::SimpleValueType InTy, TreePattern &TP); bool UpdateNodeType(unsigned ResNo, ValueTypeByHwMode InTy, TreePattern &TP); // Update node type with types inferred from an instruction operand or result // def from the ins/outs lists. // Return true if the type changed. bool UpdateNodeTypeFromInst(unsigned ResNo, Record *Operand, TreePattern &TP); /// ContainsUnresolvedType - Return true if this tree contains any /// unresolved types. bool ContainsUnresolvedType(TreePattern &TP) const; /// canPatternMatch - If it is impossible for this pattern to match on this /// target, fill in Reason and return false. Otherwise, return true. bool canPatternMatch(std::string &Reason, const CodeGenDAGPatterns &CDP); }; inline raw_ostream &operator<<(raw_ostream &OS, const TreePatternNode &TPN) { TPN.print(OS); return OS; } /// TreePattern - Represent a pattern, used for instructions, pattern /// fragments, etc. /// class TreePattern { /// Trees - The list of pattern trees which corresponds to this pattern. /// Note that PatFrag's only have a single tree. /// std::vector Trees; /// NamedNodes - This is all of the nodes that have names in the trees in this /// pattern. StringMap> NamedNodes; /// TheRecord - The actual TableGen record corresponding to this pattern. /// Record *TheRecord; /// Args - This is a list of all of the arguments to this pattern (for /// PatFrag patterns), which are the 'node' markers in this pattern. std::vector Args; /// CDP - the top-level object coordinating this madness. /// CodeGenDAGPatterns &CDP; /// isInputPattern - True if this is an input pattern, something to match. /// False if this is an output pattern, something to emit. bool isInputPattern; /// hasError - True if the currently processed nodes have unresolvable types /// or other non-fatal errors bool HasError; /// It's important that the usage of operands in ComplexPatterns is /// consistent: each named operand can be defined by at most one /// ComplexPattern. This records the ComplexPattern instance and the operand /// number for each operand encountered in a ComplexPattern to aid in that /// check. StringMap> ComplexPatternOperands; TypeInfer Infer; public: /// TreePattern constructor - Parse the specified DagInits into the /// current record. TreePattern(Record *TheRec, ListInit *RawPat, bool isInput, CodeGenDAGPatterns &ise); TreePattern(Record *TheRec, DagInit *Pat, bool isInput, CodeGenDAGPatterns &ise); TreePattern(Record *TheRec, TreePatternNodePtr Pat, bool isInput, CodeGenDAGPatterns &ise); /// getTrees - Return the tree patterns which corresponds to this pattern. /// const std::vector &getTrees() const { return Trees; } unsigned getNumTrees() const { return Trees.size(); } const TreePatternNodePtr &getTree(unsigned i) const { return Trees[i]; } void setTree(unsigned i, TreePatternNodePtr Tree) { Trees[i] = Tree; } const TreePatternNodePtr &getOnlyTree() const { assert(Trees.size() == 1 && "Doesn't have exactly one pattern!"); return Trees[0]; } const StringMap> &getNamedNodesMap() { if (NamedNodes.empty()) ComputeNamedNodes(); return NamedNodes; } /// getRecord - Return the actual TableGen record corresponding to this /// pattern. /// Record *getRecord() const { return TheRecord; } unsigned getNumArgs() const { return Args.size(); } const std::string &getArgName(unsigned i) const { assert(i < Args.size() && "Argument reference out of range!"); return Args[i]; } std::vector &getArgList() { return Args; } CodeGenDAGPatterns &getDAGPatterns() const { return CDP; } /// InlinePatternFragments - If this pattern refers to any pattern /// fragments, inline them into place, giving us a pattern without any /// PatFrags references. This may increase the number of trees in the /// pattern if a PatFrags has multiple alternatives. void InlinePatternFragments() { std::vector Copy; Trees.swap(Copy); for (const TreePatternNodePtr &C : Copy) C->InlinePatternFragments(*this, Trees); } /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false /// otherwise. Bail out if a type contradiction is found. bool InferAllTypes( const StringMap> *NamedTypes = nullptr); /// error - If this is the first error in the current resolution step, /// print it and set the error flag. Otherwise, continue silently. void error(const Twine &Msg); bool hasError() const { return HasError; } void resetError() { HasError = false; } TypeInfer &getInfer() { return Infer; } void print(raw_ostream &OS) const; void dump() const; private: TreePatternNodePtr ParseTreePattern(Init *DI, StringRef OpName); void ComputeNamedNodes(); void ComputeNamedNodes(TreePatternNode &N); }; inline bool TreePatternNode::UpdateNodeType(unsigned ResNo, const TypeSetByHwMode &InTy, TreePattern &TP) { TypeSetByHwMode VTS(InTy); TP.getInfer().expandOverloads(VTS); return TP.getInfer().MergeInTypeInfo(Types[ResNo], VTS); } inline bool TreePatternNode::UpdateNodeType(unsigned ResNo, MVT::SimpleValueType InTy, TreePattern &TP) { TypeSetByHwMode VTS(InTy); TP.getInfer().expandOverloads(VTS); return TP.getInfer().MergeInTypeInfo(Types[ResNo], VTS); } inline bool TreePatternNode::UpdateNodeType(unsigned ResNo, ValueTypeByHwMode InTy, TreePattern &TP) { TypeSetByHwMode VTS(InTy); TP.getInfer().expandOverloads(VTS); return TP.getInfer().MergeInTypeInfo(Types[ResNo], VTS); } /// DAGDefaultOperand - One of these is created for each OperandWithDefaultOps /// that has a set ExecuteAlways / DefaultOps field. struct DAGDefaultOperand { std::vector DefaultOps; }; class DAGInstruction { std::vector Results; std::vector Operands; std::vector ImpResults; TreePatternNodePtr SrcPattern; TreePatternNodePtr ResultPattern; public: DAGInstruction(std::vector &&results, std::vector &&operands, std::vector &&impresults, TreePatternNodePtr srcpattern = nullptr, TreePatternNodePtr resultpattern = nullptr) : Results(std::move(results)), Operands(std::move(operands)), ImpResults(std::move(impresults)), SrcPattern(srcpattern), ResultPattern(resultpattern) {} unsigned getNumResults() const { return Results.size(); } unsigned getNumOperands() const { return Operands.size(); } unsigned getNumImpResults() const { return ImpResults.size(); } const std::vector &getImpResults() const { return ImpResults; } Record *getResult(unsigned RN) const { assert(RN < Results.size()); return Results[RN]; } Record *getOperand(unsigned ON) const { assert(ON < Operands.size()); return Operands[ON]; } Record *getImpResult(unsigned RN) const { assert(RN < ImpResults.size()); return ImpResults[RN]; } TreePatternNodePtr getSrcPattern() const { return SrcPattern; } TreePatternNodePtr getResultPattern() const { return ResultPattern; } }; /// PatternToMatch - Used by CodeGenDAGPatterns to keep tab of patterns /// processed to produce isel. class PatternToMatch { Record *SrcRecord; // Originating Record for the pattern. ListInit *Predicates; // Top level predicate conditions to match. TreePatternNodePtr SrcPattern; // Source pattern to match. TreePatternNodePtr DstPattern; // Resulting pattern. std::vector Dstregs; // Physical register defs being matched. std::string HwModeFeatures; int AddedComplexity; // Add to matching pattern complexity. bool GISelShouldIgnore; // Should GlobalISel ignore importing this pattern. unsigned ID; // Unique ID for the record. public: PatternToMatch(Record *srcrecord, ListInit *preds, TreePatternNodePtr src, TreePatternNodePtr dst, std::vector dstregs, int complexity, unsigned uid, bool ignore, const Twine &hwmodefeatures = "") : SrcRecord(srcrecord), Predicates(preds), SrcPattern(src), DstPattern(dst), Dstregs(std::move(dstregs)), HwModeFeatures(hwmodefeatures.str()), AddedComplexity(complexity), GISelShouldIgnore(ignore), ID(uid) {} Record *getSrcRecord() const { return SrcRecord; } ListInit *getPredicates() const { return Predicates; } TreePatternNode &getSrcPattern() const { return *SrcPattern; } TreePatternNodePtr getSrcPatternShared() const { return SrcPattern; } TreePatternNode &getDstPattern() const { return *DstPattern; } TreePatternNodePtr getDstPatternShared() const { return DstPattern; } const std::vector &getDstRegs() const { return Dstregs; } StringRef getHwModeFeatures() const { return HwModeFeatures; } int getAddedComplexity() const { return AddedComplexity; } bool getGISelShouldIgnore() const { return GISelShouldIgnore; } unsigned getID() const { return ID; } std::string getPredicateCheck() const; void getPredicateRecords(SmallVectorImpl &PredicateRecs) const; /// Compute the complexity metric for the input pattern. This roughly /// corresponds to the number of nodes that are covered. int getPatternComplexity(const CodeGenDAGPatterns &CGP) const; }; class CodeGenDAGPatterns { RecordKeeper &Records; CodeGenTarget Target; CodeGenIntrinsicTable Intrinsics; std::map SDNodes; std::map, LessRecordByID> SDNodeXForms; std::map ComplexPatterns; std::map, LessRecordByID> PatternFragments; std::map DefaultOperands; std::map Instructions; // Specific SDNode definitions: Record *intrinsic_void_sdnode; Record *intrinsic_w_chain_sdnode, *intrinsic_wo_chain_sdnode; /// PatternsToMatch - All of the things we are matching on the DAG. The first /// value is the pattern to match, the second pattern is the result to /// emit. std::vector PatternsToMatch; TypeSetByHwMode LegalVTS; using PatternRewriterFn = std::function; PatternRewriterFn PatternRewriter; unsigned NumScopes = 0; public: CodeGenDAGPatterns(RecordKeeper &R, PatternRewriterFn PatternRewriter = nullptr); CodeGenTarget &getTargetInfo() { return Target; } const CodeGenTarget &getTargetInfo() const { return Target; } const TypeSetByHwMode &getLegalTypes() const { return LegalVTS; } Record *getSDNodeNamed(StringRef Name) const; const SDNodeInfo &getSDNodeInfo(Record *R) const { auto F = SDNodes.find(R); assert(F != SDNodes.end() && "Unknown node!"); return F->second; } // Node transformation lookups. typedef std::pair NodeXForm; const NodeXForm &getSDNodeTransform(Record *R) const { auto F = SDNodeXForms.find(R); assert(F != SDNodeXForms.end() && "Invalid transform!"); return F->second; } const ComplexPattern &getComplexPattern(Record *R) const { auto F = ComplexPatterns.find(R); assert(F != ComplexPatterns.end() && "Unknown addressing mode!"); return F->second; } const CodeGenIntrinsic &getIntrinsic(Record *R) const { for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i) if (Intrinsics[i].TheDef == R) return Intrinsics[i]; llvm_unreachable("Unknown intrinsic!"); } const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const { if (IID - 1 < Intrinsics.size()) return Intrinsics[IID - 1]; llvm_unreachable("Bad intrinsic ID!"); } unsigned getIntrinsicID(Record *R) const { for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i) if (Intrinsics[i].TheDef == R) return i; llvm_unreachable("Unknown intrinsic!"); } const DAGDefaultOperand &getDefaultOperand(Record *R) const { auto F = DefaultOperands.find(R); assert(F != DefaultOperands.end() && "Isn't an analyzed default operand!"); return F->second; } // Pattern Fragment information. TreePattern *getPatternFragment(Record *R) const { auto F = PatternFragments.find(R); assert(F != PatternFragments.end() && "Invalid pattern fragment request!"); return F->second.get(); } TreePattern *getPatternFragmentIfRead(Record *R) const { auto F = PatternFragments.find(R); if (F == PatternFragments.end()) return nullptr; return F->second.get(); } typedef std::map, LessRecordByID>::const_iterator pf_iterator; pf_iterator pf_begin() const { return PatternFragments.begin(); } pf_iterator pf_end() const { return PatternFragments.end(); } iterator_range ptfs() const { return PatternFragments; } // Patterns to match information. typedef std::vector::const_iterator ptm_iterator; ptm_iterator ptm_begin() const { return PatternsToMatch.begin(); } ptm_iterator ptm_end() const { return PatternsToMatch.end(); } iterator_range ptms() const { return PatternsToMatch; } /// Parse the Pattern for an instruction, and insert the result in DAGInsts. typedef std::map DAGInstMap; void parseInstructionPattern(CodeGenInstruction &CGI, ListInit *Pattern, DAGInstMap &DAGInsts); const DAGInstruction &getInstruction(Record *R) const { auto F = Instructions.find(R); assert(F != Instructions.end() && "Unknown instruction!"); return F->second; } Record *get_intrinsic_void_sdnode() const { return intrinsic_void_sdnode; } Record *get_intrinsic_w_chain_sdnode() const { return intrinsic_w_chain_sdnode; } Record *get_intrinsic_wo_chain_sdnode() const { return intrinsic_wo_chain_sdnode; } unsigned allocateScope() { return ++NumScopes; } bool operandHasDefault(Record *Op) const { return Op->isSubClassOf("OperandWithDefaultOps") && !getDefaultOperand(Op).DefaultOps.empty(); } private: void ParseNodeInfo(); void ParseNodeTransforms(); void ParseComplexPatterns(); void ParsePatternFragments(bool OutFrags = false); void ParseDefaultOperands(); void ParseInstructions(); void ParsePatterns(); void ExpandHwModeBasedTypes(); void InferInstructionFlags(); void GenerateVariants(); void VerifyInstructionFlags(); void ParseOnePattern(Record *TheDef, TreePattern &Pattern, TreePattern &Result, const std::vector &InstImpResults, bool ShouldIgnore = false); void AddPatternToMatch(TreePattern *Pattern, PatternToMatch &&PTM); void FindPatternInputsAndOutputs( TreePattern &I, TreePatternNodePtr Pat, std::map &InstInputs, MapVector> &InstResults, std::vector &InstImpResults); }; inline bool SDNodeInfo::ApplyTypeConstraints(TreePatternNode &N, TreePattern &TP) const { bool MadeChange = false; for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i) MadeChange |= TypeConstraints[i].ApplyTypeConstraint(N, *this, TP); return MadeChange; } } // end namespace llvm #endif