blob: b3160552a21fef3809bef7d851f972a90b7ef6a4 [file] [log] [blame] [edit]
//===- 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 &copy_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