| //===- Patterns.h ----------------------------------------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| /// \file Contains the Pattern hierarchy alongside helper classes such as |
| /// PatFrag, MIFlagsInfo, PatternType, etc. |
| /// |
| /// These classes are used by the GlobalISel Combiner backend to help parse, |
| /// process and emit MIR patterns. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_UTILS_GLOBALISEL_PATTERNS_H |
| #define LLVM_UTILS_GLOBALISEL_PATTERNS_H |
| |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/SetVector.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/Twine.h" |
| #include <memory> |
| #include <optional> |
| #include <string> |
| |
| namespace llvm { |
| |
| class Record; |
| class SMLoc; |
| class StringInit; |
| class CodeExpansions; |
| class CodeGenInstruction; |
| |
| namespace gi { |
| |
| class CXXPredicateCode; |
| class LLTCodeGen; |
| class LLTCodeGenOrTempType; |
| class RuleMatcher; |
| |
| //===- PatternType --------------------------------------------------------===// |
| |
| /// Represent the type of a Pattern Operand. |
| /// |
| /// Types have two form: |
| /// - LLTs, which are straightforward. |
| /// - Special types, e.g. GITypeOf |
| class PatternType { |
| public: |
| static constexpr StringLiteral SpecialTyClassName = "GISpecialType"; |
| static constexpr StringLiteral TypeOfClassName = "GITypeOf"; |
| |
| enum PTKind : uint8_t { |
| PT_None, |
| |
| PT_ValueType, |
| PT_TypeOf, |
| }; |
| |
| PatternType() : Kind(PT_None), Data() {} |
| |
| static std::optional<PatternType> get(ArrayRef<SMLoc> DiagLoc, |
| const Record *R, Twine DiagCtx); |
| static PatternType getTypeOf(StringRef OpName); |
| |
| bool isNone() const { return Kind == PT_None; } |
| bool isLLT() const { return Kind == PT_ValueType; } |
| bool isSpecial() const { return isTypeOf(); } |
| bool isTypeOf() const { return Kind == PT_TypeOf; } |
| |
| StringRef getTypeOfOpName() const; |
| const Record *getLLTRecord() const; |
| |
| explicit operator bool() const { return !isNone(); } |
| |
| bool operator==(const PatternType &Other) const; |
| bool operator!=(const PatternType &Other) const { return !operator==(Other); } |
| |
| std::string str() const; |
| |
| private: |
| PatternType(PTKind Kind) : Kind(Kind), Data() {} |
| |
| PTKind Kind; |
| union DataT { |
| DataT() : Str() {} |
| |
| /// PT_ValueType -> ValueType Def. |
| const Record *Def; |
| |
| /// PT_TypeOf -> Operand name (without the '$') |
| StringRef Str; |
| } Data; |
| }; |
| |
| //===- Pattern Base Class -------------------------------------------------===// |
| |
| /// Base class for all patterns that can be written in an `apply`, `match` or |
| /// `pattern` DAG operator. |
| /// |
| /// For example: |
| /// |
| /// (apply (G_ZEXT $x, $y), (G_ZEXT $y, $z), "return isFoo(${z})") |
| /// |
| /// Creates 3 Pattern objects: |
| /// - Two CodeGenInstruction Patterns |
| /// - A CXXPattern |
| class Pattern { |
| public: |
| enum { |
| K_AnyOpcode, |
| K_CXX, |
| |
| K_CodeGenInstruction, |
| K_PatFrag, |
| K_Builtin, |
| }; |
| |
| virtual ~Pattern() = default; |
| |
| unsigned getKind() const { return Kind; } |
| const char *getKindName() const; |
| |
| bool hasName() const { return !Name.empty(); } |
| StringRef getName() const { return Name; } |
| |
| virtual void print(raw_ostream &OS, bool PrintName = true) const = 0; |
| void dump() const; |
| |
| protected: |
| Pattern(unsigned Kind, StringRef Name) : Kind(Kind), Name(Name) { |
| assert(!Name.empty() && "unnamed pattern!"); |
| } |
| |
| void printImpl(raw_ostream &OS, bool PrintName, |
| function_ref<void()> ContentPrinter) const; |
| |
| private: |
| unsigned Kind; |
| StringRef Name; |
| }; |
| |
| //===- AnyOpcodePattern ---------------------------------------------------===// |
| |
| /// `wip_match_opcode` patterns. |
| /// This matches one or more opcodes, and does not check any operands |
| /// whatsoever. |
| /// |
| /// TODO: Long-term, this needs to be removed. It's a hack around MIR |
| /// pattern matching limitations. |
| class AnyOpcodePattern : public Pattern { |
| public: |
| AnyOpcodePattern(StringRef Name) : Pattern(K_AnyOpcode, Name) {} |
| |
| static bool classof(const Pattern *P) { return P->getKind() == K_AnyOpcode; } |
| |
| void addOpcode(const CodeGenInstruction *I) { Insts.push_back(I); } |
| const auto &insts() const { return Insts; } |
| |
| void print(raw_ostream &OS, bool PrintName = true) const override; |
| |
| private: |
| SmallVector<const CodeGenInstruction *, 4> Insts; |
| }; |
| |
| //===- CXXPattern ---------------------------------------------------------===// |
| |
| /// Represents raw C++ code which may need some expansions. |
| /// |
| /// e.g. [{ return isFooBux(${src}.getReg()); }] |
| /// |
| /// For the expanded code, \see CXXPredicateCode. CXXPredicateCode objects are |
| /// created through `expandCode`. |
| /// |
| /// \see CodeExpander and \see CodeExpansions for more information on code |
| /// expansions. |
| /// |
| /// This object has two purposes: |
| /// - Represent C++ code as a pattern entry. |
| /// - Be a factory for expanded C++ code. |
| /// - It's immutable and only holds the raw code so we can expand the same |
| /// CXX pattern multiple times if we need to. |
| /// |
| /// Note that the code is always trimmed in the constructor, so leading and |
| /// trailing whitespaces are removed. This removes bloat in the output, avoids |
| /// formatting issues, but also allows us to check things like |
| /// `.startswith("return")` trivially without worrying about spaces. |
| class CXXPattern : public Pattern { |
| public: |
| CXXPattern(const StringInit &Code, StringRef Name); |
| |
| CXXPattern(StringRef Code, StringRef Name) |
| : Pattern(K_CXX, Name), RawCode(Code.trim().str()) {} |
| |
| static bool classof(const Pattern *P) { return P->getKind() == K_CXX; } |
| |
| void setIsApply(bool Value = true) { IsApply = Value; } |
| StringRef getRawCode() const { return RawCode; } |
| |
| /// Expands raw code, replacing things such as `${foo}` with their |
| /// substitution in \p CE. |
| /// |
| /// \param CE Map of Code Expansions |
| /// \param Locs SMLocs for the Code Expander, in case it needs to emit |
| /// diagnostics. |
| /// \param AddComment Optionally called to emit a comment before the expanded |
| /// code. |
| /// |
| /// \return A CXXPredicateCode object that contains the expanded code. Note |
| /// that this may or may not insert a new object. All CXXPredicateCode objects |
| /// are held in a set to avoid emitting duplicate C++ code. |
| const CXXPredicateCode & |
| expandCode(const CodeExpansions &CE, ArrayRef<SMLoc> Locs, |
| function_ref<void(raw_ostream &)> AddComment = {}) const; |
| |
| void print(raw_ostream &OS, bool PrintName = true) const override; |
| |
| private: |
| bool IsApply = false; |
| std::string RawCode; |
| }; |
| |
| //===- InstructionPattern ---------------------------------------------===// |
| |
| /// An operand for an InstructionPattern. |
| /// |
| /// Operands are composed of three elements: |
| /// - (Optional) Value |
| /// - (Optional) Name |
| /// - (Optional) Type |
| /// |
| /// Some examples: |
| /// (i32 0):$x -> V=int(0), Name='x', Type=i32 |
| /// 0:$x -> V=int(0), Name='x' |
| /// $x -> Name='x' |
| /// i32:$x -> Name='x', Type = i32 |
| class InstructionOperand { |
| public: |
| using IntImmTy = int64_t; |
| |
| InstructionOperand(IntImmTy Imm, StringRef Name, PatternType Type) |
| : Value(Imm), Name(Name), Type(Type) {} |
| |
| InstructionOperand(StringRef Name, PatternType Type) |
| : Name(Name), Type(Type) {} |
| |
| bool isNamedImmediate() const { return hasImmValue() && isNamedOperand(); } |
| |
| bool hasImmValue() const { return Value.has_value(); } |
| IntImmTy getImmValue() const { return *Value; } |
| |
| bool isNamedOperand() const { return !Name.empty(); } |
| StringRef getOperandName() const { |
| assert(isNamedOperand() && "Operand is unnamed"); |
| return Name; |
| } |
| |
| InstructionOperand withNewName(StringRef NewName) const { |
| InstructionOperand Result = *this; |
| Result.Name = NewName; |
| return Result; |
| } |
| |
| void setIsDef(bool Value = true) { Def = Value; } |
| bool isDef() const { return Def; } |
| |
| void setType(PatternType NewType) { |
| assert((!Type || (Type == NewType)) && "Overwriting type!"); |
| Type = NewType; |
| } |
| PatternType getType() const { return Type; } |
| |
| std::string describe() const; |
| void print(raw_ostream &OS) const; |
| |
| void dump() const; |
| |
| private: |
| std::optional<int64_t> Value; |
| StringRef Name; |
| PatternType Type; |
| bool Def = false; |
| }; |
| |
| /// Base class for CodeGenInstructionPattern & PatFragPattern, which handles all |
| /// the boilerplate for patterns that have a list of operands for some (pseudo) |
| /// instruction. |
| class InstructionPattern : public Pattern { |
| public: |
| virtual ~InstructionPattern() = default; |
| |
| static bool classof(const Pattern *P) { |
| return P->getKind() == K_CodeGenInstruction || P->getKind() == K_PatFrag || |
| P->getKind() == K_Builtin; |
| } |
| |
| template <typename... Ty> void addOperand(Ty &&...Init) { |
| Operands.emplace_back(std::forward<Ty>(Init)...); |
| } |
| |
| auto &operands() { return Operands; } |
| const auto &operands() const { return Operands; } |
| unsigned operands_size() const { return Operands.size(); } |
| InstructionOperand &getOperand(unsigned K) { return Operands[K]; } |
| const InstructionOperand &getOperand(unsigned K) const { return Operands[K]; } |
| |
| /// When this InstructionPattern is used as the match root, returns the |
| /// operands that must be redefined in the 'apply' pattern for the rule to be |
| /// valid. |
| /// |
| /// For most patterns, this just returns the defs. |
| /// For PatFrag this only returns the root of the PF. |
| /// |
| /// Returns an empty array on error. |
| virtual ArrayRef<InstructionOperand> getApplyDefsNeeded() const { |
| return {operands().begin(), getNumInstDefs()}; |
| } |
| |
| auto named_operands() { |
| return make_filter_range(Operands, |
| [&](auto &O) { return O.isNamedOperand(); }); |
| } |
| |
| auto named_operands() const { |
| return make_filter_range(Operands, |
| [&](auto &O) { return O.isNamedOperand(); }); |
| } |
| |
| virtual bool isVariadic() const { return false; } |
| virtual unsigned getNumInstOperands() const = 0; |
| virtual unsigned getNumInstDefs() const = 0; |
| |
| bool hasAllDefs() const { return operands_size() >= getNumInstDefs(); } |
| |
| virtual StringRef getInstName() const = 0; |
| |
| /// Diagnoses all uses of special types in this Pattern and returns true if at |
| /// least one diagnostic was emitted. |
| bool diagnoseAllSpecialTypes(ArrayRef<SMLoc> Loc, Twine Msg) const; |
| |
| void reportUnreachable(ArrayRef<SMLoc> Locs) const; |
| virtual bool checkSemantics(ArrayRef<SMLoc> Loc); |
| |
| void print(raw_ostream &OS, bool PrintName = true) const override; |
| |
| protected: |
| InstructionPattern(unsigned K, StringRef Name) : Pattern(K, Name) {} |
| |
| virtual void printExtras(raw_ostream &OS) const {} |
| |
| SmallVector<InstructionOperand, 4> Operands; |
| }; |
| |
| //===- OperandTable -------------------------------------------------------===// |
| |
| /// Maps InstructionPattern operands to their definitions. This allows us to tie |
| /// different patterns of a (apply), (match) or (patterns) set of patterns |
| /// together. |
| class OperandTable { |
| public: |
| bool addPattern(InstructionPattern *P, |
| function_ref<void(StringRef)> DiagnoseRedef); |
| |
| struct LookupResult { |
| LookupResult() = default; |
| LookupResult(InstructionPattern *Def) : Found(true), Def(Def) {} |
| |
| bool Found = false; |
| InstructionPattern *Def = nullptr; |
| |
| bool isLiveIn() const { return Found && !Def; } |
| }; |
| |
| LookupResult lookup(StringRef OpName) const { |
| if (auto It = Table.find(OpName); It != Table.end()) |
| return LookupResult(It->second); |
| return LookupResult(); |
| } |
| |
| InstructionPattern *getDef(StringRef OpName) const { |
| return lookup(OpName).Def; |
| } |
| |
| void print(raw_ostream &OS, StringRef Name = "", StringRef Indent = "") const; |
| |
| auto begin() const { return Table.begin(); } |
| auto end() const { return Table.end(); } |
| |
| void dump() const; |
| |
| private: |
| StringMap<InstructionPattern *> Table; |
| }; |
| |
| //===- CodeGenInstructionPattern ------------------------------------------===// |
| |
| /// Helper class to contain data associated with a MIFlags operand. |
| class MIFlagsInfo { |
| public: |
| void addSetFlag(const Record *R); |
| void addUnsetFlag(const Record *R); |
| void addCopyFlag(StringRef InstName); |
| |
| const auto &set_flags() const { return SetF; } |
| const auto &unset_flags() const { return UnsetF; } |
| const auto ©_flags() const { return CopyF; } |
| |
| private: |
| SetVector<StringRef> SetF, UnsetF, CopyF; |
| }; |
| |
| /// Matches an instruction, e.g. `G_ADD $x, $y, $z`. |
| class CodeGenInstructionPattern : public InstructionPattern { |
| public: |
| CodeGenInstructionPattern(const CodeGenInstruction &I, StringRef Name) |
| : InstructionPattern(K_CodeGenInstruction, Name), I(I) {} |
| |
| static bool classof(const Pattern *P) { |
| return P->getKind() == K_CodeGenInstruction; |
| } |
| |
| bool is(StringRef OpcodeName) const; |
| |
| bool hasVariadicDefs() const; |
| bool isVariadic() const override; |
| unsigned getNumInstDefs() const override; |
| unsigned getNumInstOperands() const override; |
| |
| MIFlagsInfo &getOrCreateMIFlagsInfo(); |
| const MIFlagsInfo *getMIFlagsInfo() const { return FI.get(); } |
| |
| const CodeGenInstruction &getInst() const { return I; } |
| StringRef getInstName() const override; |
| |
| private: |
| void printExtras(raw_ostream &OS) const override; |
| |
| const CodeGenInstruction &I; |
| std::unique_ptr<MIFlagsInfo> FI; |
| }; |
| |
| //===- OperandTypeChecker -------------------------------------------------===// |
| |
| /// This is a trivial type checker for all operands in a set of |
| /// InstructionPatterns. |
| /// |
| /// It infers the type of each operand, check it's consistent with the known |
| /// type of the operand, and then sets all of the types in all operands in |
| /// propagateTypes. |
| /// |
| /// It also handles verifying correctness of special types. |
| class OperandTypeChecker { |
| public: |
| OperandTypeChecker(ArrayRef<SMLoc> DiagLoc) : DiagLoc(DiagLoc) {} |
| |
| /// Step 1: Check each pattern one by one. All patterns that pass through here |
| /// are added to a common worklist so propagateTypes can access them. |
| bool check(InstructionPattern &P, |
| std::function<bool(const PatternType &)> VerifyTypeOfOperand); |
| |
| /// Step 2: Propagate all types. e.g. if one use of "$a" has type i32, make |
| /// all uses of "$a" have type i32. |
| void propagateTypes(); |
| |
| protected: |
| ArrayRef<SMLoc> DiagLoc; |
| |
| private: |
| using InconsistentTypeDiagFn = std::function<void()>; |
| |
| void PrintSeenWithTypeIn(InstructionPattern &P, StringRef OpName, |
| PatternType Ty) const; |
| |
| struct OpTypeInfo { |
| PatternType Type; |
| InconsistentTypeDiagFn PrintTypeSrcNote = []() {}; |
| }; |
| |
| StringMap<OpTypeInfo> Types; |
| |
| SmallVector<InstructionPattern *, 16> Pats; |
| }; |
| |
| //===- PatFrag ------------------------------------------------------------===// |
| |
| /// Represents a parsed GICombinePatFrag. This can be thought of as the |
| /// equivalent of a CodeGenInstruction, but for PatFragPatterns. |
| /// |
| /// PatFrags are made of 3 things: |
| /// - Out parameters (defs) |
| /// - In parameters |
| /// - A set of pattern lists (alternatives). |
| /// |
| /// If the PatFrag uses instruction patterns, the root must be one of the defs. |
| /// |
| /// Note that this DOES NOT represent the use of the PatFrag, only its |
| /// definition. The use of the PatFrag in a Pattern is represented by |
| /// PatFragPattern. |
| /// |
| /// PatFrags use the term "parameter" instead of operand because they're |
| /// essentially macros, and using that name avoids confusion. Other than that, |
| /// they're structured similarly to a MachineInstruction - all parameters |
| /// (operands) are in the same list, with defs at the start. This helps mapping |
| /// parameters to values, because, param N of a PatFrag is always operand N of a |
| /// PatFragPattern. |
| class PatFrag { |
| public: |
| static constexpr StringLiteral ClassName = "GICombinePatFrag"; |
| |
| enum ParamKind { |
| PK_Root, |
| PK_MachineOperand, |
| PK_Imm, |
| }; |
| |
| struct Param { |
| StringRef Name; |
| ParamKind Kind; |
| }; |
| |
| using ParamVec = SmallVector<Param, 4>; |
| using ParamIt = ParamVec::const_iterator; |
| |
| /// Represents an alternative of the PatFrag. When parsing a GICombinePatFrag, |
| /// this is created from its "Alternatives" list. Each alternative is a list |
| /// of patterns written wrapped in a `(pattern ...)` dag init. |
| /// |
| /// Each argument to the `pattern` DAG operator is parsed into a Pattern |
| /// instance. |
| struct Alternative { |
| OperandTable OpTable; |
| SmallVector<std::unique_ptr<Pattern>, 4> Pats; |
| }; |
| |
| explicit PatFrag(const Record &Def); |
| |
| static StringRef getParamKindStr(ParamKind OK); |
| |
| StringRef getName() const; |
| |
| const Record &getDef() const { return Def; } |
| ArrayRef<SMLoc> getLoc() const; |
| |
| Alternative &addAlternative() { return Alts.emplace_back(); } |
| const Alternative &getAlternative(unsigned K) const { return Alts[K]; } |
| unsigned num_alternatives() const { return Alts.size(); } |
| |
| void addInParam(StringRef Name, ParamKind Kind); |
| iterator_range<ParamIt> in_params() const; |
| unsigned num_in_params() const { return Params.size() - NumOutParams; } |
| |
| void addOutParam(StringRef Name, ParamKind Kind); |
| iterator_range<ParamIt> out_params() const; |
| unsigned num_out_params() const { return NumOutParams; } |
| |
| unsigned num_roots() const; |
| unsigned num_params() const { return num_in_params() + num_out_params(); } |
| |
| /// Finds the operand \p Name and returns its index or -1 if not found. |
| /// Remember that all params are part of the same list, with out params at the |
| /// start. This means that the index returned can be used to access operands |
| /// of InstructionPatterns. |
| unsigned getParamIdx(StringRef Name) const; |
| const Param &getParam(unsigned K) const { return Params[K]; } |
| |
| bool canBeMatchRoot() const { return num_roots() == 1; } |
| |
| void print(raw_ostream &OS, StringRef Indent = "") const; |
| void dump() const; |
| |
| /// Checks if the in-param \p ParamName can be unbound or not. |
| /// \p ArgName is the name of the argument passed to the PatFrag. |
| /// |
| /// An argument can be unbound only if, for all alternatives: |
| /// - There is no CXX pattern, OR: |
| /// - There is an InstructionPattern that binds the parameter. |
| /// |
| /// e.g. in (MyPatFrag $foo), if $foo has never been seen before (= it's |
| /// unbound), this checks if MyPatFrag supports it or not. |
| bool handleUnboundInParam(StringRef ParamName, StringRef ArgName, |
| ArrayRef<SMLoc> DiagLoc) const; |
| |
| bool checkSemantics(); |
| bool buildOperandsTables(); |
| |
| private: |
| static void printParamsList(raw_ostream &OS, iterator_range<ParamIt> Params); |
| |
| void PrintError(Twine Msg) const; |
| |
| const Record &Def; |
| unsigned NumOutParams = 0; |
| ParamVec Params; |
| SmallVector<Alternative, 2> Alts; |
| }; |
| |
| //===- PatFragPattern -----------------------------------------------------===// |
| |
| /// Represents a use of a GICombinePatFrag. |
| class PatFragPattern : public InstructionPattern { |
| public: |
| PatFragPattern(const PatFrag &PF, StringRef Name) |
| : InstructionPattern(K_PatFrag, Name), PF(PF) {} |
| |
| static bool classof(const Pattern *P) { return P->getKind() == K_PatFrag; } |
| |
| const PatFrag &getPatFrag() const { return PF; } |
| StringRef getInstName() const override { return PF.getName(); } |
| |
| unsigned getNumInstDefs() const override { return PF.num_out_params(); } |
| unsigned getNumInstOperands() const override { return PF.num_params(); } |
| |
| ArrayRef<InstructionOperand> getApplyDefsNeeded() const override; |
| |
| bool checkSemantics(ArrayRef<SMLoc> DiagLoc) override; |
| |
| /// Before emitting the patterns inside the PatFrag, add all necessary code |
| /// expansions to \p PatFragCEs imported from \p ParentCEs. |
| /// |
| /// For a MachineOperand PatFrag parameter, this will fetch the expansion for |
| /// that operand from \p ParentCEs and add it to \p PatFragCEs. Errors can be |
| /// emitted if the MachineOperand reference is unbound. |
| /// |
| /// For an Immediate PatFrag parameter this simply adds the integer value to |
| /// \p PatFragCEs as an expansion. |
| /// |
| /// \param ParentCEs Contains all of the code expansions declared by the other |
| /// patterns emitted so far in the pattern list containing |
| /// this PatFragPattern. |
| /// \param PatFragCEs Output Code Expansions (usually empty) |
| /// \param DiagLoc Diagnostic loc in case an error occurs. |
| /// \return `true` on success, `false` on failure. |
| bool mapInputCodeExpansions(const CodeExpansions &ParentCEs, |
| CodeExpansions &PatFragCEs, |
| ArrayRef<SMLoc> DiagLoc) const; |
| |
| private: |
| const PatFrag &PF; |
| }; |
| |
| //===- BuiltinPattern -----------------------------------------------------===// |
| |
| /// Represents builtin instructions such as "GIReplaceReg" and "GIEraseRoot". |
| enum BuiltinKind { |
| BI_ReplaceReg, |
| BI_EraseRoot, |
| }; |
| |
| class BuiltinPattern : public InstructionPattern { |
| struct BuiltinInfo { |
| StringLiteral DefName; |
| BuiltinKind Kind; |
| unsigned NumOps; |
| unsigned NumDefs; |
| }; |
| |
| static constexpr std::array<BuiltinInfo, 2> KnownBuiltins = {{ |
| {"GIReplaceReg", BI_ReplaceReg, 2, 1}, |
| {"GIEraseRoot", BI_EraseRoot, 0, 0}, |
| }}; |
| |
| public: |
| static constexpr StringLiteral ClassName = "GIBuiltinInst"; |
| |
| BuiltinPattern(const Record &Def, StringRef Name) |
| : InstructionPattern(K_Builtin, Name), I(getBuiltinInfo(Def)) {} |
| |
| static bool classof(const Pattern *P) { return P->getKind() == K_Builtin; } |
| |
| unsigned getNumInstOperands() const override { return I.NumOps; } |
| unsigned getNumInstDefs() const override { return I.NumDefs; } |
| StringRef getInstName() const override { return I.DefName; } |
| BuiltinKind getBuiltinKind() const { return I.Kind; } |
| |
| bool checkSemantics(ArrayRef<SMLoc> Loc) override; |
| |
| private: |
| static BuiltinInfo getBuiltinInfo(const Record &Def); |
| |
| BuiltinInfo I; |
| }; |
| |
| } // namespace gi |
| } // end namespace llvm |
| |
| #endif // ifndef LLVM_UTILS_GLOBALISEL_PATTERNS_H |