452 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			452 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
| //=== 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 {
 | |
|     PointerUnion<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
 |