1*0fca6ea1SDimitry Andric //===- Patterns.h ----------------------------------------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric /// \file Contains the Pattern hierarchy alongside helper classes such as 10*0fca6ea1SDimitry Andric /// PatFrag, MIFlagsInfo, PatternType, etc. 11*0fca6ea1SDimitry Andric /// 12*0fca6ea1SDimitry Andric /// These classes are used by the GlobalISel Combiner backend to help parse, 13*0fca6ea1SDimitry Andric /// process and emit MIR patterns. 14*0fca6ea1SDimitry Andric // 15*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 16*0fca6ea1SDimitry Andric 17*0fca6ea1SDimitry Andric #ifndef LLVM_UTILS_GLOBALISEL_PATTERNS_H 18*0fca6ea1SDimitry Andric #define LLVM_UTILS_GLOBALISEL_PATTERNS_H 19*0fca6ea1SDimitry Andric 20*0fca6ea1SDimitry Andric #include "llvm/ADT/ArrayRef.h" 21*0fca6ea1SDimitry Andric #include "llvm/ADT/SetVector.h" 22*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 23*0fca6ea1SDimitry Andric #include "llvm/ADT/StringMap.h" 24*0fca6ea1SDimitry Andric #include "llvm/ADT/StringRef.h" 25*0fca6ea1SDimitry Andric #include "llvm/ADT/Twine.h" 26*0fca6ea1SDimitry Andric #include <memory> 27*0fca6ea1SDimitry Andric #include <optional> 28*0fca6ea1SDimitry Andric #include <string> 29*0fca6ea1SDimitry Andric 30*0fca6ea1SDimitry Andric namespace llvm { 31*0fca6ea1SDimitry Andric 32*0fca6ea1SDimitry Andric class Record; 33*0fca6ea1SDimitry Andric class SMLoc; 34*0fca6ea1SDimitry Andric class StringInit; 35*0fca6ea1SDimitry Andric class CodeExpansions; 36*0fca6ea1SDimitry Andric class CodeGenInstruction; 37*0fca6ea1SDimitry Andric struct CodeGenIntrinsic; 38*0fca6ea1SDimitry Andric 39*0fca6ea1SDimitry Andric namespace gi { 40*0fca6ea1SDimitry Andric 41*0fca6ea1SDimitry Andric class CXXPredicateCode; 42*0fca6ea1SDimitry Andric class LLTCodeGen; 43*0fca6ea1SDimitry Andric class LLTCodeGenOrTempType; 44*0fca6ea1SDimitry Andric class RuleMatcher; 45*0fca6ea1SDimitry Andric 46*0fca6ea1SDimitry Andric //===- PatternType --------------------------------------------------------===// 47*0fca6ea1SDimitry Andric 48*0fca6ea1SDimitry Andric /// Represent the type of a Pattern Operand. 49*0fca6ea1SDimitry Andric /// 50*0fca6ea1SDimitry Andric /// Types have two form: 51*0fca6ea1SDimitry Andric /// - LLTs, which are straightforward. 52*0fca6ea1SDimitry Andric /// - Special types, e.g. GITypeOf 53*0fca6ea1SDimitry Andric class PatternType { 54*0fca6ea1SDimitry Andric public: 55*0fca6ea1SDimitry Andric static constexpr StringLiteral SpecialTyClassName = "GISpecialType"; 56*0fca6ea1SDimitry Andric static constexpr StringLiteral TypeOfClassName = "GITypeOf"; 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric enum PTKind : uint8_t { 59*0fca6ea1SDimitry Andric PT_None, 60*0fca6ea1SDimitry Andric 61*0fca6ea1SDimitry Andric PT_ValueType, 62*0fca6ea1SDimitry Andric PT_TypeOf, 63*0fca6ea1SDimitry Andric }; 64*0fca6ea1SDimitry Andric 65*0fca6ea1SDimitry Andric PatternType() : Kind(PT_None), Data() {} 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric static std::optional<PatternType> get(ArrayRef<SMLoc> DiagLoc, 68*0fca6ea1SDimitry Andric const Record *R, Twine DiagCtx); 69*0fca6ea1SDimitry Andric static PatternType getTypeOf(StringRef OpName); 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric bool isNone() const { return Kind == PT_None; } 72*0fca6ea1SDimitry Andric bool isLLT() const { return Kind == PT_ValueType; } 73*0fca6ea1SDimitry Andric bool isSpecial() const { return isTypeOf(); } 74*0fca6ea1SDimitry Andric bool isTypeOf() const { return Kind == PT_TypeOf; } 75*0fca6ea1SDimitry Andric 76*0fca6ea1SDimitry Andric StringRef getTypeOfOpName() const; 77*0fca6ea1SDimitry Andric const Record *getLLTRecord() const; 78*0fca6ea1SDimitry Andric 79*0fca6ea1SDimitry Andric explicit operator bool() const { return !isNone(); } 80*0fca6ea1SDimitry Andric 81*0fca6ea1SDimitry Andric bool operator==(const PatternType &Other) const; 82*0fca6ea1SDimitry Andric bool operator!=(const PatternType &Other) const { return !operator==(Other); } 83*0fca6ea1SDimitry Andric 84*0fca6ea1SDimitry Andric std::string str() const; 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric private: 87*0fca6ea1SDimitry Andric PatternType(PTKind Kind) : Kind(Kind), Data() {} 88*0fca6ea1SDimitry Andric 89*0fca6ea1SDimitry Andric PTKind Kind; 90*0fca6ea1SDimitry Andric union DataT { 91*0fca6ea1SDimitry Andric DataT() : Str() {} 92*0fca6ea1SDimitry Andric 93*0fca6ea1SDimitry Andric /// PT_ValueType -> ValueType Def. 94*0fca6ea1SDimitry Andric const Record *Def; 95*0fca6ea1SDimitry Andric 96*0fca6ea1SDimitry Andric /// PT_TypeOf -> Operand name (without the '$') 97*0fca6ea1SDimitry Andric StringRef Str; 98*0fca6ea1SDimitry Andric } Data; 99*0fca6ea1SDimitry Andric }; 100*0fca6ea1SDimitry Andric 101*0fca6ea1SDimitry Andric //===- Pattern Base Class -------------------------------------------------===// 102*0fca6ea1SDimitry Andric 103*0fca6ea1SDimitry Andric /// Base class for all patterns that can be written in an `apply`, `match` or 104*0fca6ea1SDimitry Andric /// `pattern` DAG operator. 105*0fca6ea1SDimitry Andric /// 106*0fca6ea1SDimitry Andric /// For example: 107*0fca6ea1SDimitry Andric /// 108*0fca6ea1SDimitry Andric /// (apply (G_ZEXT $x, $y), (G_ZEXT $y, $z), "return isFoo(${z})") 109*0fca6ea1SDimitry Andric /// 110*0fca6ea1SDimitry Andric /// Creates 3 Pattern objects: 111*0fca6ea1SDimitry Andric /// - Two CodeGenInstruction Patterns 112*0fca6ea1SDimitry Andric /// - A CXXPattern 113*0fca6ea1SDimitry Andric class Pattern { 114*0fca6ea1SDimitry Andric public: 115*0fca6ea1SDimitry Andric enum { 116*0fca6ea1SDimitry Andric K_AnyOpcode, 117*0fca6ea1SDimitry Andric K_CXX, 118*0fca6ea1SDimitry Andric 119*0fca6ea1SDimitry Andric K_CodeGenInstruction, 120*0fca6ea1SDimitry Andric K_PatFrag, 121*0fca6ea1SDimitry Andric K_Builtin, 122*0fca6ea1SDimitry Andric }; 123*0fca6ea1SDimitry Andric 124*0fca6ea1SDimitry Andric virtual ~Pattern() = default; 125*0fca6ea1SDimitry Andric 126*0fca6ea1SDimitry Andric unsigned getKind() const { return Kind; } 127*0fca6ea1SDimitry Andric const char *getKindName() const; 128*0fca6ea1SDimitry Andric 129*0fca6ea1SDimitry Andric bool hasName() const { return !Name.empty(); } 130*0fca6ea1SDimitry Andric StringRef getName() const { return Name; } 131*0fca6ea1SDimitry Andric 132*0fca6ea1SDimitry Andric virtual void print(raw_ostream &OS, bool PrintName = true) const = 0; 133*0fca6ea1SDimitry Andric void dump() const; 134*0fca6ea1SDimitry Andric 135*0fca6ea1SDimitry Andric protected: 136*0fca6ea1SDimitry Andric Pattern(unsigned Kind, StringRef Name) : Kind(Kind), Name(Name) { 137*0fca6ea1SDimitry Andric assert(!Name.empty() && "unnamed pattern!"); 138*0fca6ea1SDimitry Andric } 139*0fca6ea1SDimitry Andric 140*0fca6ea1SDimitry Andric void printImpl(raw_ostream &OS, bool PrintName, 141*0fca6ea1SDimitry Andric function_ref<void()> ContentPrinter) const; 142*0fca6ea1SDimitry Andric 143*0fca6ea1SDimitry Andric private: 144*0fca6ea1SDimitry Andric unsigned Kind; 145*0fca6ea1SDimitry Andric StringRef Name; 146*0fca6ea1SDimitry Andric }; 147*0fca6ea1SDimitry Andric 148*0fca6ea1SDimitry Andric //===- AnyOpcodePattern ---------------------------------------------------===// 149*0fca6ea1SDimitry Andric 150*0fca6ea1SDimitry Andric /// `wip_match_opcode` patterns. 151*0fca6ea1SDimitry Andric /// This matches one or more opcodes, and does not check any operands 152*0fca6ea1SDimitry Andric /// whatsoever. 153*0fca6ea1SDimitry Andric /// 154*0fca6ea1SDimitry Andric /// TODO: Long-term, this needs to be removed. It's a hack around MIR 155*0fca6ea1SDimitry Andric /// pattern matching limitations. 156*0fca6ea1SDimitry Andric class AnyOpcodePattern : public Pattern { 157*0fca6ea1SDimitry Andric public: 158*0fca6ea1SDimitry Andric AnyOpcodePattern(StringRef Name) : Pattern(K_AnyOpcode, Name) {} 159*0fca6ea1SDimitry Andric 160*0fca6ea1SDimitry Andric static bool classof(const Pattern *P) { return P->getKind() == K_AnyOpcode; } 161*0fca6ea1SDimitry Andric 162*0fca6ea1SDimitry Andric void addOpcode(const CodeGenInstruction *I) { Insts.push_back(I); } 163*0fca6ea1SDimitry Andric const auto &insts() const { return Insts; } 164*0fca6ea1SDimitry Andric 165*0fca6ea1SDimitry Andric void print(raw_ostream &OS, bool PrintName = true) const override; 166*0fca6ea1SDimitry Andric 167*0fca6ea1SDimitry Andric private: 168*0fca6ea1SDimitry Andric SmallVector<const CodeGenInstruction *, 4> Insts; 169*0fca6ea1SDimitry Andric }; 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric //===- CXXPattern ---------------------------------------------------------===// 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric /// Represents raw C++ code which may need some expansions. 174*0fca6ea1SDimitry Andric /// 175*0fca6ea1SDimitry Andric /// e.g. [{ return isFooBux(${src}.getReg()); }] 176*0fca6ea1SDimitry Andric /// 177*0fca6ea1SDimitry Andric /// For the expanded code, \see CXXPredicateCode. CXXPredicateCode objects are 178*0fca6ea1SDimitry Andric /// created through `expandCode`. 179*0fca6ea1SDimitry Andric /// 180*0fca6ea1SDimitry Andric /// \see CodeExpander and \see CodeExpansions for more information on code 181*0fca6ea1SDimitry Andric /// expansions. 182*0fca6ea1SDimitry Andric /// 183*0fca6ea1SDimitry Andric /// This object has two purposes: 184*0fca6ea1SDimitry Andric /// - Represent C++ code as a pattern entry. 185*0fca6ea1SDimitry Andric /// - Be a factory for expanded C++ code. 186*0fca6ea1SDimitry Andric /// - It's immutable and only holds the raw code so we can expand the same 187*0fca6ea1SDimitry Andric /// CXX pattern multiple times if we need to. 188*0fca6ea1SDimitry Andric /// 189*0fca6ea1SDimitry Andric /// Note that the code is always trimmed in the constructor, so leading and 190*0fca6ea1SDimitry Andric /// trailing whitespaces are removed. This removes bloat in the output, avoids 191*0fca6ea1SDimitry Andric /// formatting issues, but also allows us to check things like 192*0fca6ea1SDimitry Andric /// `.startswith("return")` trivially without worrying about spaces. 193*0fca6ea1SDimitry Andric class CXXPattern : public Pattern { 194*0fca6ea1SDimitry Andric public: 195*0fca6ea1SDimitry Andric CXXPattern(const StringInit &Code, StringRef Name); 196*0fca6ea1SDimitry Andric 197*0fca6ea1SDimitry Andric CXXPattern(StringRef Code, StringRef Name) 198*0fca6ea1SDimitry Andric : Pattern(K_CXX, Name), RawCode(Code.trim().str()) {} 199*0fca6ea1SDimitry Andric 200*0fca6ea1SDimitry Andric static bool classof(const Pattern *P) { return P->getKind() == K_CXX; } 201*0fca6ea1SDimitry Andric 202*0fca6ea1SDimitry Andric void setIsApply(bool Value = true) { IsApply = Value; } 203*0fca6ea1SDimitry Andric StringRef getRawCode() const { return RawCode; } 204*0fca6ea1SDimitry Andric 205*0fca6ea1SDimitry Andric /// Expands raw code, replacing things such as `${foo}` with their 206*0fca6ea1SDimitry Andric /// substitution in \p CE. 207*0fca6ea1SDimitry Andric /// 208*0fca6ea1SDimitry Andric /// Can only be used on 'match' CXX Patterns. 'apply' CXX pattern emission 209*0fca6ea1SDimitry Andric /// is handled differently as we emit both the 'match' and 'apply' part 210*0fca6ea1SDimitry Andric /// together in a single Custom CXX Action. 211*0fca6ea1SDimitry Andric /// 212*0fca6ea1SDimitry Andric /// \param CE Map of Code Expansions 213*0fca6ea1SDimitry Andric /// \param Locs SMLocs for the Code Expander, in case it needs to emit 214*0fca6ea1SDimitry Andric /// diagnostics. 215*0fca6ea1SDimitry Andric /// \param AddComment Optionally called to emit a comment before the expanded 216*0fca6ea1SDimitry Andric /// code. 217*0fca6ea1SDimitry Andric /// 218*0fca6ea1SDimitry Andric /// \return A CXXPredicateCode object that contains the expanded code. Note 219*0fca6ea1SDimitry Andric /// that this may or may not insert a new object. All CXXPredicateCode objects 220*0fca6ea1SDimitry Andric /// are held in a set to avoid emitting duplicate C++ code. 221*0fca6ea1SDimitry Andric const CXXPredicateCode & 222*0fca6ea1SDimitry Andric expandCode(const CodeExpansions &CE, ArrayRef<SMLoc> Locs, 223*0fca6ea1SDimitry Andric function_ref<void(raw_ostream &)> AddComment = {}) const; 224*0fca6ea1SDimitry Andric 225*0fca6ea1SDimitry Andric void print(raw_ostream &OS, bool PrintName = true) const override; 226*0fca6ea1SDimitry Andric 227*0fca6ea1SDimitry Andric private: 228*0fca6ea1SDimitry Andric bool IsApply = false; 229*0fca6ea1SDimitry Andric std::string RawCode; 230*0fca6ea1SDimitry Andric }; 231*0fca6ea1SDimitry Andric 232*0fca6ea1SDimitry Andric //===- InstructionPattern ---------------------------------------------===// 233*0fca6ea1SDimitry Andric 234*0fca6ea1SDimitry Andric /// An operand for an InstructionPattern. 235*0fca6ea1SDimitry Andric /// 236*0fca6ea1SDimitry Andric /// Operands are composed of three elements: 237*0fca6ea1SDimitry Andric /// - (Optional) Value 238*0fca6ea1SDimitry Andric /// - (Optional) Name 239*0fca6ea1SDimitry Andric /// - (Optional) Type 240*0fca6ea1SDimitry Andric /// 241*0fca6ea1SDimitry Andric /// Some examples: 242*0fca6ea1SDimitry Andric /// (i32 0):$x -> V=int(0), Name='x', Type=i32 243*0fca6ea1SDimitry Andric /// 0:$x -> V=int(0), Name='x' 244*0fca6ea1SDimitry Andric /// $x -> Name='x' 245*0fca6ea1SDimitry Andric /// i32:$x -> Name='x', Type = i32 246*0fca6ea1SDimitry Andric class InstructionOperand { 247*0fca6ea1SDimitry Andric public: 248*0fca6ea1SDimitry Andric using IntImmTy = int64_t; 249*0fca6ea1SDimitry Andric 250*0fca6ea1SDimitry Andric InstructionOperand(IntImmTy Imm, StringRef Name, PatternType Type) 251*0fca6ea1SDimitry Andric : Value(Imm), Name(Name), Type(Type) {} 252*0fca6ea1SDimitry Andric 253*0fca6ea1SDimitry Andric InstructionOperand(StringRef Name, PatternType Type) 254*0fca6ea1SDimitry Andric : Name(Name), Type(Type) {} 255*0fca6ea1SDimitry Andric 256*0fca6ea1SDimitry Andric bool isNamedImmediate() const { return hasImmValue() && isNamedOperand(); } 257*0fca6ea1SDimitry Andric 258*0fca6ea1SDimitry Andric bool hasImmValue() const { return Value.has_value(); } 259*0fca6ea1SDimitry Andric IntImmTy getImmValue() const { return *Value; } 260*0fca6ea1SDimitry Andric 261*0fca6ea1SDimitry Andric bool isNamedOperand() const { return !Name.empty(); } 262*0fca6ea1SDimitry Andric StringRef getOperandName() const { 263*0fca6ea1SDimitry Andric assert(isNamedOperand() && "Operand is unnamed"); 264*0fca6ea1SDimitry Andric return Name; 265*0fca6ea1SDimitry Andric } 266*0fca6ea1SDimitry Andric 267*0fca6ea1SDimitry Andric InstructionOperand withNewName(StringRef NewName) const { 268*0fca6ea1SDimitry Andric InstructionOperand Result = *this; 269*0fca6ea1SDimitry Andric Result.Name = NewName; 270*0fca6ea1SDimitry Andric return Result; 271*0fca6ea1SDimitry Andric } 272*0fca6ea1SDimitry Andric 273*0fca6ea1SDimitry Andric void setIsDef(bool Value = true) { Def = Value; } 274*0fca6ea1SDimitry Andric bool isDef() const { return Def; } 275*0fca6ea1SDimitry Andric 276*0fca6ea1SDimitry Andric void setType(PatternType NewType) { 277*0fca6ea1SDimitry Andric assert((!Type || (Type == NewType)) && "Overwriting type!"); 278*0fca6ea1SDimitry Andric Type = NewType; 279*0fca6ea1SDimitry Andric } 280*0fca6ea1SDimitry Andric PatternType getType() const { return Type; } 281*0fca6ea1SDimitry Andric 282*0fca6ea1SDimitry Andric std::string describe() const; 283*0fca6ea1SDimitry Andric void print(raw_ostream &OS) const; 284*0fca6ea1SDimitry Andric 285*0fca6ea1SDimitry Andric void dump() const; 286*0fca6ea1SDimitry Andric 287*0fca6ea1SDimitry Andric private: 288*0fca6ea1SDimitry Andric std::optional<int64_t> Value; 289*0fca6ea1SDimitry Andric StringRef Name; 290*0fca6ea1SDimitry Andric PatternType Type; 291*0fca6ea1SDimitry Andric bool Def = false; 292*0fca6ea1SDimitry Andric }; 293*0fca6ea1SDimitry Andric 294*0fca6ea1SDimitry Andric /// Base class for CodeGenInstructionPattern & PatFragPattern, which handles all 295*0fca6ea1SDimitry Andric /// the boilerplate for patterns that have a list of operands for some (pseudo) 296*0fca6ea1SDimitry Andric /// instruction. 297*0fca6ea1SDimitry Andric class InstructionPattern : public Pattern { 298*0fca6ea1SDimitry Andric public: 299*0fca6ea1SDimitry Andric virtual ~InstructionPattern() = default; 300*0fca6ea1SDimitry Andric 301*0fca6ea1SDimitry Andric static bool classof(const Pattern *P) { 302*0fca6ea1SDimitry Andric return P->getKind() == K_CodeGenInstruction || P->getKind() == K_PatFrag || 303*0fca6ea1SDimitry Andric P->getKind() == K_Builtin; 304*0fca6ea1SDimitry Andric } 305*0fca6ea1SDimitry Andric 306*0fca6ea1SDimitry Andric template <typename... Ty> void addOperand(Ty &&...Init) { 307*0fca6ea1SDimitry Andric Operands.emplace_back(std::forward<Ty>(Init)...); 308*0fca6ea1SDimitry Andric } 309*0fca6ea1SDimitry Andric 310*0fca6ea1SDimitry Andric auto &operands() { return Operands; } 311*0fca6ea1SDimitry Andric const auto &operands() const { return Operands; } 312*0fca6ea1SDimitry Andric unsigned operands_size() const { return Operands.size(); } 313*0fca6ea1SDimitry Andric InstructionOperand &getOperand(unsigned K) { return Operands[K]; } 314*0fca6ea1SDimitry Andric const InstructionOperand &getOperand(unsigned K) const { return Operands[K]; } 315*0fca6ea1SDimitry Andric 316*0fca6ea1SDimitry Andric /// When this InstructionPattern is used as the match root, returns the 317*0fca6ea1SDimitry Andric /// operands that must be redefined in the 'apply' pattern for the rule to be 318*0fca6ea1SDimitry Andric /// valid. 319*0fca6ea1SDimitry Andric /// 320*0fca6ea1SDimitry Andric /// For most patterns, this just returns the defs. 321*0fca6ea1SDimitry Andric /// For PatFrag this only returns the root of the PF. 322*0fca6ea1SDimitry Andric /// 323*0fca6ea1SDimitry Andric /// Returns an empty array on error. 324*0fca6ea1SDimitry Andric virtual ArrayRef<InstructionOperand> getApplyDefsNeeded() const { 325*0fca6ea1SDimitry Andric return {operands().begin(), getNumInstDefs()}; 326*0fca6ea1SDimitry Andric } 327*0fca6ea1SDimitry Andric 328*0fca6ea1SDimitry Andric auto named_operands() { 329*0fca6ea1SDimitry Andric return make_filter_range(Operands, 330*0fca6ea1SDimitry Andric [&](auto &O) { return O.isNamedOperand(); }); 331*0fca6ea1SDimitry Andric } 332*0fca6ea1SDimitry Andric 333*0fca6ea1SDimitry Andric auto named_operands() const { 334*0fca6ea1SDimitry Andric return make_filter_range(Operands, 335*0fca6ea1SDimitry Andric [&](auto &O) { return O.isNamedOperand(); }); 336*0fca6ea1SDimitry Andric } 337*0fca6ea1SDimitry Andric 338*0fca6ea1SDimitry Andric virtual bool isVariadic() const { return false; } 339*0fca6ea1SDimitry Andric virtual unsigned getNumInstOperands() const = 0; 340*0fca6ea1SDimitry Andric virtual unsigned getNumInstDefs() const = 0; 341*0fca6ea1SDimitry Andric 342*0fca6ea1SDimitry Andric bool hasAllDefs() const { return operands_size() >= getNumInstDefs(); } 343*0fca6ea1SDimitry Andric 344*0fca6ea1SDimitry Andric virtual StringRef getInstName() const = 0; 345*0fca6ea1SDimitry Andric 346*0fca6ea1SDimitry Andric /// Diagnoses all uses of special types in this Pattern and returns true if at 347*0fca6ea1SDimitry Andric /// least one diagnostic was emitted. 348*0fca6ea1SDimitry Andric bool diagnoseAllSpecialTypes(ArrayRef<SMLoc> Loc, Twine Msg) const; 349*0fca6ea1SDimitry Andric 350*0fca6ea1SDimitry Andric void reportUnreachable(ArrayRef<SMLoc> Locs) const; 351*0fca6ea1SDimitry Andric virtual bool checkSemantics(ArrayRef<SMLoc> Loc); 352*0fca6ea1SDimitry Andric 353*0fca6ea1SDimitry Andric void print(raw_ostream &OS, bool PrintName = true) const override; 354*0fca6ea1SDimitry Andric 355*0fca6ea1SDimitry Andric protected: 356*0fca6ea1SDimitry Andric InstructionPattern(unsigned K, StringRef Name) : Pattern(K, Name) {} 357*0fca6ea1SDimitry Andric 358*0fca6ea1SDimitry Andric virtual void printExtras(raw_ostream &OS) const {} 359*0fca6ea1SDimitry Andric 360*0fca6ea1SDimitry Andric SmallVector<InstructionOperand, 4> Operands; 361*0fca6ea1SDimitry Andric }; 362*0fca6ea1SDimitry Andric 363*0fca6ea1SDimitry Andric //===- OperandTable -------------------------------------------------------===// 364*0fca6ea1SDimitry Andric 365*0fca6ea1SDimitry Andric /// Maps InstructionPattern operands to their definitions. This allows us to tie 366*0fca6ea1SDimitry Andric /// different patterns of a (apply), (match) or (patterns) set of patterns 367*0fca6ea1SDimitry Andric /// together. 368*0fca6ea1SDimitry Andric class OperandTable { 369*0fca6ea1SDimitry Andric public: 370*0fca6ea1SDimitry Andric bool addPattern(InstructionPattern *P, 371*0fca6ea1SDimitry Andric function_ref<void(StringRef)> DiagnoseRedef); 372*0fca6ea1SDimitry Andric 373*0fca6ea1SDimitry Andric struct LookupResult { 374*0fca6ea1SDimitry Andric LookupResult() = default; 375*0fca6ea1SDimitry Andric LookupResult(InstructionPattern *Def) : Found(true), Def(Def) {} 376*0fca6ea1SDimitry Andric 377*0fca6ea1SDimitry Andric bool Found = false; 378*0fca6ea1SDimitry Andric InstructionPattern *Def = nullptr; 379*0fca6ea1SDimitry Andric 380*0fca6ea1SDimitry Andric bool isLiveIn() const { return Found && !Def; } 381*0fca6ea1SDimitry Andric }; 382*0fca6ea1SDimitry Andric 383*0fca6ea1SDimitry Andric LookupResult lookup(StringRef OpName) const { 384*0fca6ea1SDimitry Andric if (auto It = Table.find(OpName); It != Table.end()) 385*0fca6ea1SDimitry Andric return LookupResult(It->second); 386*0fca6ea1SDimitry Andric return LookupResult(); 387*0fca6ea1SDimitry Andric } 388*0fca6ea1SDimitry Andric 389*0fca6ea1SDimitry Andric InstructionPattern *getDef(StringRef OpName) const { 390*0fca6ea1SDimitry Andric return lookup(OpName).Def; 391*0fca6ea1SDimitry Andric } 392*0fca6ea1SDimitry Andric 393*0fca6ea1SDimitry Andric void print(raw_ostream &OS, StringRef Name = "", StringRef Indent = "") const; 394*0fca6ea1SDimitry Andric 395*0fca6ea1SDimitry Andric auto begin() const { return Table.begin(); } 396*0fca6ea1SDimitry Andric auto end() const { return Table.end(); } 397*0fca6ea1SDimitry Andric 398*0fca6ea1SDimitry Andric void dump() const; 399*0fca6ea1SDimitry Andric 400*0fca6ea1SDimitry Andric private: 401*0fca6ea1SDimitry Andric StringMap<InstructionPattern *> Table; 402*0fca6ea1SDimitry Andric }; 403*0fca6ea1SDimitry Andric 404*0fca6ea1SDimitry Andric //===- MIFlagsInfo --------------------------------------------------------===// 405*0fca6ea1SDimitry Andric 406*0fca6ea1SDimitry Andric /// Helper class to contain data associated with a MIFlags operand. 407*0fca6ea1SDimitry Andric class MIFlagsInfo { 408*0fca6ea1SDimitry Andric public: 409*0fca6ea1SDimitry Andric void addSetFlag(const Record *R); 410*0fca6ea1SDimitry Andric void addUnsetFlag(const Record *R); 411*0fca6ea1SDimitry Andric void addCopyFlag(StringRef InstName); 412*0fca6ea1SDimitry Andric 413*0fca6ea1SDimitry Andric const auto &set_flags() const { return SetF; } 414*0fca6ea1SDimitry Andric const auto &unset_flags() const { return UnsetF; } 415*0fca6ea1SDimitry Andric const auto ©_flags() const { return CopyF; } 416*0fca6ea1SDimitry Andric 417*0fca6ea1SDimitry Andric private: 418*0fca6ea1SDimitry Andric SetVector<StringRef> SetF, UnsetF, CopyF; 419*0fca6ea1SDimitry Andric }; 420*0fca6ea1SDimitry Andric 421*0fca6ea1SDimitry Andric //===- CodeGenInstructionPattern ------------------------------------------===// 422*0fca6ea1SDimitry Andric 423*0fca6ea1SDimitry Andric /// Matches an instruction or intrinsic: 424*0fca6ea1SDimitry Andric /// e.g. `G_ADD $x, $y, $z` or `int_amdgcn_cos $a` 425*0fca6ea1SDimitry Andric /// 426*0fca6ea1SDimitry Andric /// Intrinsics are just normal instructions with a special operand for intrinsic 427*0fca6ea1SDimitry Andric /// ID. Despite G_INTRINSIC opcodes being variadic, we consider that the 428*0fca6ea1SDimitry Andric /// Intrinsic's info takes priority. This means we return: 429*0fca6ea1SDimitry Andric /// - false for isVariadic() and other variadic-related queries. 430*0fca6ea1SDimitry Andric /// - getNumInstDefs and getNumInstOperands use the intrinsic's in/out 431*0fca6ea1SDimitry Andric /// operands. 432*0fca6ea1SDimitry Andric class CodeGenInstructionPattern : public InstructionPattern { 433*0fca6ea1SDimitry Andric public: 434*0fca6ea1SDimitry Andric CodeGenInstructionPattern(const CodeGenInstruction &I, StringRef Name) 435*0fca6ea1SDimitry Andric : InstructionPattern(K_CodeGenInstruction, Name), I(I) {} 436*0fca6ea1SDimitry Andric 437*0fca6ea1SDimitry Andric static bool classof(const Pattern *P) { 438*0fca6ea1SDimitry Andric return P->getKind() == K_CodeGenInstruction; 439*0fca6ea1SDimitry Andric } 440*0fca6ea1SDimitry Andric 441*0fca6ea1SDimitry Andric bool is(StringRef OpcodeName) const; 442*0fca6ea1SDimitry Andric 443*0fca6ea1SDimitry Andric void setIntrinsic(const CodeGenIntrinsic *I) { IntrinInfo = I; } 444*0fca6ea1SDimitry Andric const CodeGenIntrinsic *getIntrinsic() const { return IntrinInfo; } 445*0fca6ea1SDimitry Andric bool isIntrinsic() const { return IntrinInfo; } 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric bool hasVariadicDefs() const; 448*0fca6ea1SDimitry Andric bool isVariadic() const override; 449*0fca6ea1SDimitry Andric unsigned getNumInstDefs() const override; 450*0fca6ea1SDimitry Andric unsigned getNumInstOperands() const override; 451*0fca6ea1SDimitry Andric 452*0fca6ea1SDimitry Andric MIFlagsInfo &getOrCreateMIFlagsInfo(); 453*0fca6ea1SDimitry Andric const MIFlagsInfo *getMIFlagsInfo() const { return FI.get(); } 454*0fca6ea1SDimitry Andric 455*0fca6ea1SDimitry Andric const CodeGenInstruction &getInst() const { return I; } 456*0fca6ea1SDimitry Andric StringRef getInstName() const override; 457*0fca6ea1SDimitry Andric 458*0fca6ea1SDimitry Andric private: 459*0fca6ea1SDimitry Andric void printExtras(raw_ostream &OS) const override; 460*0fca6ea1SDimitry Andric 461*0fca6ea1SDimitry Andric const CodeGenInstruction &I; 462*0fca6ea1SDimitry Andric const CodeGenIntrinsic *IntrinInfo = nullptr; 463*0fca6ea1SDimitry Andric std::unique_ptr<MIFlagsInfo> FI; 464*0fca6ea1SDimitry Andric }; 465*0fca6ea1SDimitry Andric 466*0fca6ea1SDimitry Andric //===- OperandTypeChecker -------------------------------------------------===// 467*0fca6ea1SDimitry Andric 468*0fca6ea1SDimitry Andric /// This is a trivial type checker for all operands in a set of 469*0fca6ea1SDimitry Andric /// InstructionPatterns. 470*0fca6ea1SDimitry Andric /// 471*0fca6ea1SDimitry Andric /// It infers the type of each operand, check it's consistent with the known 472*0fca6ea1SDimitry Andric /// type of the operand, and then sets all of the types in all operands in 473*0fca6ea1SDimitry Andric /// propagateTypes. 474*0fca6ea1SDimitry Andric /// 475*0fca6ea1SDimitry Andric /// It also handles verifying correctness of special types. 476*0fca6ea1SDimitry Andric class OperandTypeChecker { 477*0fca6ea1SDimitry Andric public: 478*0fca6ea1SDimitry Andric OperandTypeChecker(ArrayRef<SMLoc> DiagLoc) : DiagLoc(DiagLoc) {} 479*0fca6ea1SDimitry Andric 480*0fca6ea1SDimitry Andric /// Step 1: Check each pattern one by one. All patterns that pass through here 481*0fca6ea1SDimitry Andric /// are added to a common worklist so propagateTypes can access them. 482*0fca6ea1SDimitry Andric bool check(InstructionPattern &P, 483*0fca6ea1SDimitry Andric std::function<bool(const PatternType &)> VerifyTypeOfOperand); 484*0fca6ea1SDimitry Andric 485*0fca6ea1SDimitry Andric /// Step 2: Propagate all types. e.g. if one use of "$a" has type i32, make 486*0fca6ea1SDimitry Andric /// all uses of "$a" have type i32. 487*0fca6ea1SDimitry Andric void propagateTypes(); 488*0fca6ea1SDimitry Andric 489*0fca6ea1SDimitry Andric protected: 490*0fca6ea1SDimitry Andric ArrayRef<SMLoc> DiagLoc; 491*0fca6ea1SDimitry Andric 492*0fca6ea1SDimitry Andric private: 493*0fca6ea1SDimitry Andric using InconsistentTypeDiagFn = std::function<void()>; 494*0fca6ea1SDimitry Andric 495*0fca6ea1SDimitry Andric void PrintSeenWithTypeIn(InstructionPattern &P, StringRef OpName, 496*0fca6ea1SDimitry Andric PatternType Ty) const; 497*0fca6ea1SDimitry Andric 498*0fca6ea1SDimitry Andric struct OpTypeInfo { 499*0fca6ea1SDimitry Andric PatternType Type; 500*0fca6ea1SDimitry Andric InconsistentTypeDiagFn PrintTypeSrcNote = []() {}; 501*0fca6ea1SDimitry Andric }; 502*0fca6ea1SDimitry Andric 503*0fca6ea1SDimitry Andric StringMap<OpTypeInfo> Types; 504*0fca6ea1SDimitry Andric 505*0fca6ea1SDimitry Andric SmallVector<InstructionPattern *, 16> Pats; 506*0fca6ea1SDimitry Andric }; 507*0fca6ea1SDimitry Andric 508*0fca6ea1SDimitry Andric //===- PatFrag ------------------------------------------------------------===// 509*0fca6ea1SDimitry Andric 510*0fca6ea1SDimitry Andric /// Represents a parsed GICombinePatFrag. This can be thought of as the 511*0fca6ea1SDimitry Andric /// equivalent of a CodeGenInstruction, but for PatFragPatterns. 512*0fca6ea1SDimitry Andric /// 513*0fca6ea1SDimitry Andric /// PatFrags are made of 3 things: 514*0fca6ea1SDimitry Andric /// - Out parameters (defs) 515*0fca6ea1SDimitry Andric /// - In parameters 516*0fca6ea1SDimitry Andric /// - A set of pattern lists (alternatives). 517*0fca6ea1SDimitry Andric /// 518*0fca6ea1SDimitry Andric /// If the PatFrag uses instruction patterns, the root must be one of the defs. 519*0fca6ea1SDimitry Andric /// 520*0fca6ea1SDimitry Andric /// Note that this DOES NOT represent the use of the PatFrag, only its 521*0fca6ea1SDimitry Andric /// definition. The use of the PatFrag in a Pattern is represented by 522*0fca6ea1SDimitry Andric /// PatFragPattern. 523*0fca6ea1SDimitry Andric /// 524*0fca6ea1SDimitry Andric /// PatFrags use the term "parameter" instead of operand because they're 525*0fca6ea1SDimitry Andric /// essentially macros, and using that name avoids confusion. Other than that, 526*0fca6ea1SDimitry Andric /// they're structured similarly to a MachineInstruction - all parameters 527*0fca6ea1SDimitry Andric /// (operands) are in the same list, with defs at the start. This helps mapping 528*0fca6ea1SDimitry Andric /// parameters to values, because, param N of a PatFrag is always operand N of a 529*0fca6ea1SDimitry Andric /// PatFragPattern. 530*0fca6ea1SDimitry Andric class PatFrag { 531*0fca6ea1SDimitry Andric public: 532*0fca6ea1SDimitry Andric static constexpr StringLiteral ClassName = "GICombinePatFrag"; 533*0fca6ea1SDimitry Andric 534*0fca6ea1SDimitry Andric enum ParamKind { 535*0fca6ea1SDimitry Andric PK_Root, 536*0fca6ea1SDimitry Andric PK_MachineOperand, 537*0fca6ea1SDimitry Andric PK_Imm, 538*0fca6ea1SDimitry Andric }; 539*0fca6ea1SDimitry Andric 540*0fca6ea1SDimitry Andric struct Param { 541*0fca6ea1SDimitry Andric StringRef Name; 542*0fca6ea1SDimitry Andric ParamKind Kind; 543*0fca6ea1SDimitry Andric }; 544*0fca6ea1SDimitry Andric 545*0fca6ea1SDimitry Andric using ParamVec = SmallVector<Param, 4>; 546*0fca6ea1SDimitry Andric using ParamIt = ParamVec::const_iterator; 547*0fca6ea1SDimitry Andric 548*0fca6ea1SDimitry Andric /// Represents an alternative of the PatFrag. When parsing a GICombinePatFrag, 549*0fca6ea1SDimitry Andric /// this is created from its "Alternatives" list. Each alternative is a list 550*0fca6ea1SDimitry Andric /// of patterns written wrapped in a `(pattern ...)` dag init. 551*0fca6ea1SDimitry Andric /// 552*0fca6ea1SDimitry Andric /// Each argument to the `pattern` DAG operator is parsed into a Pattern 553*0fca6ea1SDimitry Andric /// instance. 554*0fca6ea1SDimitry Andric struct Alternative { 555*0fca6ea1SDimitry Andric OperandTable OpTable; 556*0fca6ea1SDimitry Andric SmallVector<std::unique_ptr<Pattern>, 4> Pats; 557*0fca6ea1SDimitry Andric }; 558*0fca6ea1SDimitry Andric 559*0fca6ea1SDimitry Andric explicit PatFrag(const Record &Def); 560*0fca6ea1SDimitry Andric 561*0fca6ea1SDimitry Andric static StringRef getParamKindStr(ParamKind OK); 562*0fca6ea1SDimitry Andric 563*0fca6ea1SDimitry Andric StringRef getName() const; 564*0fca6ea1SDimitry Andric 565*0fca6ea1SDimitry Andric const Record &getDef() const { return Def; } 566*0fca6ea1SDimitry Andric ArrayRef<SMLoc> getLoc() const; 567*0fca6ea1SDimitry Andric 568*0fca6ea1SDimitry Andric Alternative &addAlternative() { return Alts.emplace_back(); } 569*0fca6ea1SDimitry Andric const Alternative &getAlternative(unsigned K) const { return Alts[K]; } 570*0fca6ea1SDimitry Andric unsigned num_alternatives() const { return Alts.size(); } 571*0fca6ea1SDimitry Andric 572*0fca6ea1SDimitry Andric void addInParam(StringRef Name, ParamKind Kind); 573*0fca6ea1SDimitry Andric iterator_range<ParamIt> in_params() const; 574*0fca6ea1SDimitry Andric unsigned num_in_params() const { return Params.size() - NumOutParams; } 575*0fca6ea1SDimitry Andric 576*0fca6ea1SDimitry Andric void addOutParam(StringRef Name, ParamKind Kind); 577*0fca6ea1SDimitry Andric iterator_range<ParamIt> out_params() const; 578*0fca6ea1SDimitry Andric unsigned num_out_params() const { return NumOutParams; } 579*0fca6ea1SDimitry Andric 580*0fca6ea1SDimitry Andric unsigned num_roots() const; 581*0fca6ea1SDimitry Andric unsigned num_params() const { return num_in_params() + num_out_params(); } 582*0fca6ea1SDimitry Andric 583*0fca6ea1SDimitry Andric /// Finds the operand \p Name and returns its index or -1 if not found. 584*0fca6ea1SDimitry Andric /// Remember that all params are part of the same list, with out params at the 585*0fca6ea1SDimitry Andric /// start. This means that the index returned can be used to access operands 586*0fca6ea1SDimitry Andric /// of InstructionPatterns. 587*0fca6ea1SDimitry Andric unsigned getParamIdx(StringRef Name) const; 588*0fca6ea1SDimitry Andric const Param &getParam(unsigned K) const { return Params[K]; } 589*0fca6ea1SDimitry Andric 590*0fca6ea1SDimitry Andric bool canBeMatchRoot() const { return num_roots() == 1; } 591*0fca6ea1SDimitry Andric 592*0fca6ea1SDimitry Andric void print(raw_ostream &OS, StringRef Indent = "") const; 593*0fca6ea1SDimitry Andric void dump() const; 594*0fca6ea1SDimitry Andric 595*0fca6ea1SDimitry Andric /// Checks if the in-param \p ParamName can be unbound or not. 596*0fca6ea1SDimitry Andric /// \p ArgName is the name of the argument passed to the PatFrag. 597*0fca6ea1SDimitry Andric /// 598*0fca6ea1SDimitry Andric /// An argument can be unbound only if, for all alternatives: 599*0fca6ea1SDimitry Andric /// - There is no CXX pattern, OR: 600*0fca6ea1SDimitry Andric /// - There is an InstructionPattern that binds the parameter. 601*0fca6ea1SDimitry Andric /// 602*0fca6ea1SDimitry Andric /// e.g. in (MyPatFrag $foo), if $foo has never been seen before (= it's 603*0fca6ea1SDimitry Andric /// unbound), this checks if MyPatFrag supports it or not. 604*0fca6ea1SDimitry Andric bool handleUnboundInParam(StringRef ParamName, StringRef ArgName, 605*0fca6ea1SDimitry Andric ArrayRef<SMLoc> DiagLoc) const; 606*0fca6ea1SDimitry Andric 607*0fca6ea1SDimitry Andric bool checkSemantics(); 608*0fca6ea1SDimitry Andric bool buildOperandsTables(); 609*0fca6ea1SDimitry Andric 610*0fca6ea1SDimitry Andric private: 611*0fca6ea1SDimitry Andric static void printParamsList(raw_ostream &OS, iterator_range<ParamIt> Params); 612*0fca6ea1SDimitry Andric 613*0fca6ea1SDimitry Andric void PrintError(Twine Msg) const; 614*0fca6ea1SDimitry Andric 615*0fca6ea1SDimitry Andric const Record &Def; 616*0fca6ea1SDimitry Andric unsigned NumOutParams = 0; 617*0fca6ea1SDimitry Andric ParamVec Params; 618*0fca6ea1SDimitry Andric SmallVector<Alternative, 2> Alts; 619*0fca6ea1SDimitry Andric }; 620*0fca6ea1SDimitry Andric 621*0fca6ea1SDimitry Andric //===- PatFragPattern -----------------------------------------------------===// 622*0fca6ea1SDimitry Andric 623*0fca6ea1SDimitry Andric /// Represents a use of a GICombinePatFrag. 624*0fca6ea1SDimitry Andric class PatFragPattern : public InstructionPattern { 625*0fca6ea1SDimitry Andric public: 626*0fca6ea1SDimitry Andric PatFragPattern(const PatFrag &PF, StringRef Name) 627*0fca6ea1SDimitry Andric : InstructionPattern(K_PatFrag, Name), PF(PF) {} 628*0fca6ea1SDimitry Andric 629*0fca6ea1SDimitry Andric static bool classof(const Pattern *P) { return P->getKind() == K_PatFrag; } 630*0fca6ea1SDimitry Andric 631*0fca6ea1SDimitry Andric const PatFrag &getPatFrag() const { return PF; } 632*0fca6ea1SDimitry Andric StringRef getInstName() const override { return PF.getName(); } 633*0fca6ea1SDimitry Andric 634*0fca6ea1SDimitry Andric unsigned getNumInstDefs() const override { return PF.num_out_params(); } 635*0fca6ea1SDimitry Andric unsigned getNumInstOperands() const override { return PF.num_params(); } 636*0fca6ea1SDimitry Andric 637*0fca6ea1SDimitry Andric ArrayRef<InstructionOperand> getApplyDefsNeeded() const override; 638*0fca6ea1SDimitry Andric 639*0fca6ea1SDimitry Andric bool checkSemantics(ArrayRef<SMLoc> DiagLoc) override; 640*0fca6ea1SDimitry Andric 641*0fca6ea1SDimitry Andric /// Before emitting the patterns inside the PatFrag, add all necessary code 642*0fca6ea1SDimitry Andric /// expansions to \p PatFragCEs imported from \p ParentCEs. 643*0fca6ea1SDimitry Andric /// 644*0fca6ea1SDimitry Andric /// For a MachineOperand PatFrag parameter, this will fetch the expansion for 645*0fca6ea1SDimitry Andric /// that operand from \p ParentCEs and add it to \p PatFragCEs. Errors can be 646*0fca6ea1SDimitry Andric /// emitted if the MachineOperand reference is unbound. 647*0fca6ea1SDimitry Andric /// 648*0fca6ea1SDimitry Andric /// For an Immediate PatFrag parameter this simply adds the integer value to 649*0fca6ea1SDimitry Andric /// \p PatFragCEs as an expansion. 650*0fca6ea1SDimitry Andric /// 651*0fca6ea1SDimitry Andric /// \param ParentCEs Contains all of the code expansions declared by the other 652*0fca6ea1SDimitry Andric /// patterns emitted so far in the pattern list containing 653*0fca6ea1SDimitry Andric /// this PatFragPattern. 654*0fca6ea1SDimitry Andric /// \param PatFragCEs Output Code Expansions (usually empty) 655*0fca6ea1SDimitry Andric /// \param DiagLoc Diagnostic loc in case an error occurs. 656*0fca6ea1SDimitry Andric /// \return `true` on success, `false` on failure. 657*0fca6ea1SDimitry Andric bool mapInputCodeExpansions(const CodeExpansions &ParentCEs, 658*0fca6ea1SDimitry Andric CodeExpansions &PatFragCEs, 659*0fca6ea1SDimitry Andric ArrayRef<SMLoc> DiagLoc) const; 660*0fca6ea1SDimitry Andric 661*0fca6ea1SDimitry Andric private: 662*0fca6ea1SDimitry Andric const PatFrag &PF; 663*0fca6ea1SDimitry Andric }; 664*0fca6ea1SDimitry Andric 665*0fca6ea1SDimitry Andric //===- BuiltinPattern -----------------------------------------------------===// 666*0fca6ea1SDimitry Andric 667*0fca6ea1SDimitry Andric /// Represents builtin instructions such as "GIReplaceReg" and "GIEraseRoot". 668*0fca6ea1SDimitry Andric enum BuiltinKind { 669*0fca6ea1SDimitry Andric BI_ReplaceReg, 670*0fca6ea1SDimitry Andric BI_EraseRoot, 671*0fca6ea1SDimitry Andric }; 672*0fca6ea1SDimitry Andric 673*0fca6ea1SDimitry Andric class BuiltinPattern : public InstructionPattern { 674*0fca6ea1SDimitry Andric struct BuiltinInfo { 675*0fca6ea1SDimitry Andric StringLiteral DefName; 676*0fca6ea1SDimitry Andric BuiltinKind Kind; 677*0fca6ea1SDimitry Andric unsigned NumOps; 678*0fca6ea1SDimitry Andric unsigned NumDefs; 679*0fca6ea1SDimitry Andric }; 680*0fca6ea1SDimitry Andric 681*0fca6ea1SDimitry Andric static constexpr std::array<BuiltinInfo, 2> KnownBuiltins = {{ 682*0fca6ea1SDimitry Andric {"GIReplaceReg", BI_ReplaceReg, 2, 1}, 683*0fca6ea1SDimitry Andric {"GIEraseRoot", BI_EraseRoot, 0, 0}, 684*0fca6ea1SDimitry Andric }}; 685*0fca6ea1SDimitry Andric 686*0fca6ea1SDimitry Andric public: 687*0fca6ea1SDimitry Andric static constexpr StringLiteral ClassName = "GIBuiltinInst"; 688*0fca6ea1SDimitry Andric 689*0fca6ea1SDimitry Andric BuiltinPattern(const Record &Def, StringRef Name) 690*0fca6ea1SDimitry Andric : InstructionPattern(K_Builtin, Name), I(getBuiltinInfo(Def)) {} 691*0fca6ea1SDimitry Andric 692*0fca6ea1SDimitry Andric static bool classof(const Pattern *P) { return P->getKind() == K_Builtin; } 693*0fca6ea1SDimitry Andric 694*0fca6ea1SDimitry Andric unsigned getNumInstOperands() const override { return I.NumOps; } 695*0fca6ea1SDimitry Andric unsigned getNumInstDefs() const override { return I.NumDefs; } 696*0fca6ea1SDimitry Andric StringRef getInstName() const override { return I.DefName; } 697*0fca6ea1SDimitry Andric BuiltinKind getBuiltinKind() const { return I.Kind; } 698*0fca6ea1SDimitry Andric 699*0fca6ea1SDimitry Andric bool checkSemantics(ArrayRef<SMLoc> Loc) override; 700*0fca6ea1SDimitry Andric 701*0fca6ea1SDimitry Andric private: 702*0fca6ea1SDimitry Andric static BuiltinInfo getBuiltinInfo(const Record &Def); 703*0fca6ea1SDimitry Andric 704*0fca6ea1SDimitry Andric BuiltinInfo I; 705*0fca6ea1SDimitry Andric }; 706*0fca6ea1SDimitry Andric 707*0fca6ea1SDimitry Andric } // namespace gi 708*0fca6ea1SDimitry Andric } // end namespace llvm 709*0fca6ea1SDimitry Andric 710*0fca6ea1SDimitry Andric #endif // ifndef LLVM_UTILS_GLOBALISEL_PATTERNS_H 711