123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- //=== unittests/CodeGen/IRMatchers.h - Match on the LLVM IR -----*- 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
- /// This file provides a simple mechanism for performing search operations over
- /// IR including metadata and types. It allows writing complex search patterns
- /// using understandable syntax. For instance, the code:
- ///
- /// \code
- /// const BasicBlock *BB = ...
- /// const Instruction *I = match(BB,
- /// MInstruction(Instruction::Store,
- /// MConstInt(4, 8),
- /// MMTuple(
- /// MMTuple(
- /// MMString("omnipotent char"),
- /// MMTuple(
- /// MMString("Simple C/C++ TBAA")),
- /// MConstInt(0, 64)),
- /// MSameAs(0),
- /// MConstInt(0))));
- /// \endcode
- ///
- /// searches the basic block BB for the 'store' instruction, first argument of
- /// which is 'i8 4', and the attached metadata has an item described by the
- /// given tree.
- //===----------------------------------------------------------------------===//
- #ifndef CLANG_UNITTESTS_CODEGEN_IRMATCHERS_H
- #define CLANG_UNITTESTS_CODEGEN_IRMATCHERS_H
- #include "llvm/ADT/PointerUnion.h"
- #include "llvm/IR/BasicBlock.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/Instruction.h"
- #include "llvm/IR/Metadata.h"
- #include "llvm/IR/Value.h"
- namespace llvm {
- /// Keeps information about pending match queries.
- ///
- /// This class stores state of all unfinished match actions. It allows to
- /// use queries like "this operand is the same as n-th operand", which are
- /// hard to implement otherwise.
- ///
- class MatcherContext {
- public:
- /// Describes pending match query.
- ///
- /// The query is represented by the current entity being investigated (type,
- /// value or metadata). If the entity is a member of a list (like arguments),
- /// the query also keeps the entity number in that list.
- ///
- class Query {
- PointerUnion3<const Value *, const Metadata *, const Type *> Entity;
- unsigned OperandNo;
- public:
- Query(const Value *V, unsigned N) : Entity(V), OperandNo(N) {}
- Query(const Metadata *M, unsigned N) : Entity(M), OperandNo(N) {}
- Query(const Type *T, unsigned N) : Entity(T), OperandNo(N) {}
- template<typename T>
- const T *get() const {
- return Entity.dyn_cast<const T *>();
- }
- unsigned getOperandNo() const { return OperandNo; }
- };
- template<typename T>
- void push(const T *V, unsigned N = ~0) {
- MatchStack.push_back(Query(V, N));
- }
- void pop() { MatchStack.pop_back(); }
- template<typename T>
- const T *top() const { return MatchStack.back().get<T>(); }
- size_t size() const { return MatchStack.size(); }
- unsigned getOperandNo() const { return MatchStack.back().getOperandNo(); }
- /// Returns match query at the given offset from the top of queries.
- ///
- /// Offset 0 corresponds to the topmost query.
- ///
- const Query &getQuery(unsigned Offset) const {
- assert(MatchStack.size() > Offset);
- return MatchStack[MatchStack.size() - 1 - Offset];
- }
- private:
- SmallVector<Query, 8> MatchStack;
- };
- /// Base of all matcher classes.
- ///
- class Matcher {
- public:
- virtual ~Matcher() {}
- /// Returns true if the entity on the top of the specified context satisfies
- /// the matcher condition.
- ///
- virtual bool match(MatcherContext &MC) = 0;
- };
- /// Base class of matchers that test particular entity.
- ///
- template<typename T>
- class EntityMatcher : public Matcher {
- public:
- bool match(MatcherContext &MC) override {
- if (auto V = MC.top<T>())
- return matchEntity(*V, MC);
- return false;
- }
- virtual bool matchEntity(const T &M, MatcherContext &C) = 0;
- };
- /// Matcher that matches any entity of the specified kind.
- ///
- template<typename T>
- class AnyMatcher : public EntityMatcher<T> {
- public:
- bool matchEntity(const T &M, MatcherContext &C) override { return true; }
- };
- /// Matcher that tests if the current entity satisfies the specified
- /// condition.
- ///
- template<typename T>
- class CondMatcher : public EntityMatcher<T> {
- std::function<bool(const T &)> Condition;
- public:
- CondMatcher(std::function<bool(const T &)> C) : Condition(C) {}
- bool matchEntity(const T &V, MatcherContext &C) override {
- return Condition(V);
- }
- };
- /// Matcher that save pointer to the entity that satisfies condition of the
- // specified matcher.
- ///
- template<typename T>
- class SavingMatcher : public EntityMatcher<T> {
- const T *&Var;
- std::shared_ptr<Matcher> Next;
- public:
- SavingMatcher(const T *&V, std::shared_ptr<Matcher> N) : Var(V), Next(N) {}
- bool matchEntity(const T &V, MatcherContext &C) override {
- bool Result = Next->match(C);
- if (Result)
- Var = &V;
- return Result;
- }
- };
- /// Matcher that checks that the entity is identical to another entity in the
- /// same container.
- ///
- class SameAsMatcher : public Matcher {
- unsigned OpNo;
- public:
- SameAsMatcher(unsigned N) : OpNo(N) {}
- bool match(MatcherContext &C) override {
- if (C.getOperandNo() != ~0U) {
- // Handle all known containers here.
- const MatcherContext::Query &StackRec = C.getQuery(1);
- if (const Metadata *MR = StackRec.get<Metadata>()) {
- if (const auto *MT = dyn_cast<MDTuple>(MR)) {
- if (OpNo < MT->getNumOperands())
- return C.top<Metadata>() == MT->getOperand(OpNo).get();
- return false;
- }
- llvm_unreachable("Unknown metadata container");
- }
- if (const Value *VR = StackRec.get<Value>()) {
- if (const auto *Insn = dyn_cast<Instruction>(VR)) {
- if (OpNo < Insn->getNumOperands())
- return C.top<Value>() == Insn->getOperand(OpNo);
- return false;
- }
- llvm_unreachable("Unknown value container");
- }
- llvm_unreachable("Unknown type container");
- }
- return false;
- }
- };
- /// Matcher that tests if the entity is a constant integer.
- ///
- class ConstantIntMatcher : public Matcher {
- uint64_t IntValue;
- unsigned Width;
- public:
- ConstantIntMatcher(uint64_t V, unsigned W = 0) : IntValue(V), Width(W) {}
- bool match(MatcherContext &Ctx) override {
- if (const Value *V = Ctx.top<Value>()) {
- if (const auto *CI = dyn_cast<ConstantInt>(V))
- return (Width == 0 || CI->getBitWidth() == Width) &&
- CI->getLimitedValue() == IntValue;
- }
- if (const Metadata *M = Ctx.top<Metadata>()) {
- if (const auto *MT = dyn_cast<ValueAsMetadata>(M))
- if (const auto *C = dyn_cast<ConstantInt>(MT->getValue()))
- return (Width == 0 || C->getBitWidth() == Width) &&
- C->getLimitedValue() == IntValue;
- }
- return false;
- }
- };
- /// Value matcher tuned to test instructions.
- ///
- class InstructionMatcher : public EntityMatcher<Value> {
- SmallVector<std::shared_ptr<Matcher>, 8> OperandMatchers;
- std::shared_ptr<EntityMatcher<Metadata>> MetaMatcher = nullptr;
- unsigned Code;
- public:
- InstructionMatcher(unsigned C) : Code(C) {}
- void push(std::shared_ptr<EntityMatcher<Metadata>> M) {
- assert(!MetaMatcher && "Only one metadata matcher may be specified");
- MetaMatcher = M;
- }
- void push(std::shared_ptr<Matcher> V) { OperandMatchers.push_back(V); }
- template<typename... Args>
- void push(std::shared_ptr<Matcher> V, Args... A) {
- push(V);
- push(A...);
- }
- virtual bool matchInstruction(const Instruction &I) {
- return I.getOpcode() == Code;
- }
- bool matchEntity(const Value &V, MatcherContext &C) override {
- if (const auto *I = dyn_cast<Instruction>(&V)) {
- if (!matchInstruction(*I))
- return false;
- if (OperandMatchers.size() > I->getNumOperands())
- return false;
- for (unsigned N = 0, E = OperandMatchers.size(); N != E; ++N) {
- C.push(I->getOperand(N), N);
- if (!OperandMatchers[N]->match(C)) {
- C.pop();
- return false;
- }
- C.pop();
- }
- if (MetaMatcher) {
- SmallVector<std::pair<unsigned, MDNode *>, 8> MDs;
- I->getAllMetadata(MDs);
- bool Found = false;
- for (auto Item : MDs) {
- C.push(Item.second);
- if (MetaMatcher->match(C)) {
- Found = true;
- C.pop();
- break;
- }
- C.pop();
- }
- return Found;
- }
- return true;
- }
- return false;
- }
- };
- /// Matcher that tests type of the current value using the specified
- /// type matcher.
- ///
- class ValueTypeMatcher : public EntityMatcher<Value> {
- std::shared_ptr<EntityMatcher<Type>> TyM;
- public:
- ValueTypeMatcher(std::shared_ptr<EntityMatcher<Type>> T) : TyM(T) {}
- ValueTypeMatcher(const Type *T)
- : TyM(new CondMatcher<Type>([T](const Type &Ty) -> bool {
- return &Ty == T;
- })) {}
- bool matchEntity(const Value &V, MatcherContext &Ctx) override {
- Type *Ty = V.getType();
- Ctx.push(Ty);
- bool Res = TyM->match(Ctx);
- Ctx.pop();
- return Res;
- }
- };
- /// Matcher that matches string metadata.
- ///
- class NameMetaMatcher : public EntityMatcher<Metadata> {
- StringRef Name;
- public:
- NameMetaMatcher(StringRef N) : Name(N) {}
- bool matchEntity(const Metadata &M, MatcherContext &C) override {
- if (auto *MDS = dyn_cast<MDString>(&M))
- return MDS->getString().equals(Name);
- return false;
- }
- };
- /// Matcher that matches metadata tuples.
- ///
- class MTupleMatcher : public EntityMatcher<Metadata> {
- SmallVector<std::shared_ptr<Matcher>, 4> Operands;
- public:
- void push(std::shared_ptr<Matcher> M) { Operands.push_back(M); }
- template<typename... Args>
- void push(std::shared_ptr<Matcher> M, Args... A) {
- push(M);
- push(A...);
- }
- bool matchEntity(const Metadata &M, MatcherContext &C) override {
- if (const auto *MT = dyn_cast<MDTuple>(&M)) {
- if (MT->getNumOperands() != Operands.size())
- return false;
- for (unsigned I = 0, E = MT->getNumOperands(); I != E; ++I) {
- const MDOperand &Op = MT->getOperand(I);
- C.push(Op.get(), I);
- if (!Operands[I]->match(C)) {
- C.pop();
- return false;
- }
- C.pop();
- }
- return true;
- }
- return false;
- }
- };
- // Helper function used to construct matchers.
- inline std::shared_ptr<Matcher> MSameAs(unsigned N) {
- return std::shared_ptr<Matcher>(new SameAsMatcher(N));
- }
- template<typename... T>
- std::shared_ptr<InstructionMatcher> MInstruction(unsigned C, T... Args) {
- auto Result = new InstructionMatcher(C);
- Result->push(Args...);
- return std::shared_ptr<InstructionMatcher>(Result);
- }
- inline std::shared_ptr<Matcher> MConstInt(uint64_t V, unsigned W = 0) {
- return std::shared_ptr<Matcher>(new ConstantIntMatcher(V, W));
- }
- inline std::shared_ptr<EntityMatcher<Value>>
- MValType(std::shared_ptr<EntityMatcher<Type>> T) {
- return std::shared_ptr<EntityMatcher<Value>>(new ValueTypeMatcher(T));
- }
- inline std::shared_ptr<EntityMatcher<Value>> MValType(const Type *T) {
- return std::shared_ptr<EntityMatcher<Value>>(new ValueTypeMatcher(T));
- }
- inline std::shared_ptr<EntityMatcher<Type>>
- MType(std::function<bool(const Type &)> C) {
- return std::shared_ptr<EntityMatcher<Type>>(new CondMatcher<Type>(C));
- }
- inline std::shared_ptr<EntityMatcher<Metadata>> MMAny() {
- return std::shared_ptr<EntityMatcher<Metadata>>(new AnyMatcher<Metadata>);
- }
- inline std::shared_ptr<EntityMatcher<Metadata>>
- MMSave(const Metadata *&V, std::shared_ptr<EntityMatcher<Metadata>> M) {
- return std::shared_ptr<EntityMatcher<Metadata>>(
- new SavingMatcher<Metadata>(V, M));
- }
- inline std::shared_ptr<EntityMatcher<Metadata>> MMString(const char *Name) {
- return std::shared_ptr<EntityMatcher<Metadata>>(new NameMetaMatcher(Name));
- }
- template<typename... T>
- std::shared_ptr<EntityMatcher<Metadata>> MMTuple(T... Args) {
- auto Res = new MTupleMatcher();
- Res->push(Args...);
- return std::shared_ptr<EntityMatcher<Metadata>>(Res);
- }
- /// Looks for the instruction that satisfies condition of the specified
- /// matcher inside the given basic block.
- /// \returns Pointer to the found instruction or nullptr if such instruction
- /// was not found.
- ///
- inline const Instruction *match(const BasicBlock *BB,
- std::shared_ptr<Matcher> M) {
- MatcherContext MC;
- for (const auto &I : *BB) {
- MC.push(&I);
- if (M->match(MC))
- return &I;
- MC.pop();
- }
- assert(MC.size() == 0);
- return nullptr;
- }
- /// Looks for the instruction that satisfies condition of the specified
- /// matcher starting from the specified instruction inside the same basic block.
- ///
- /// The given instruction is not checked.
- ///
- inline const Instruction *matchNext(const Instruction *I, std::shared_ptr<Matcher> M) {
- if (!I)
- return nullptr;
- MatcherContext MC;
- const BasicBlock *BB = I->getParent();
- if (!BB)
- return nullptr;
- for (auto P = ++BasicBlock::const_iterator(I), E = BB->end(); P != E; ++P) {
- MC.push(&*P);
- if (M->match(MC))
- return &*P;
- MC.pop();
- }
- assert(MC.size() == 0);
- return nullptr;
- }
- }
- #endif
|