123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- PtrUseVisitor.h - InstVisitors over a pointers uses ------*- 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 collection of visitors which walk the (instruction)
- /// uses of a pointer. These visitors all provide the same essential behavior
- /// as an InstVisitor with similar template-based flexibility and
- /// implementation strategies.
- ///
- /// These can be used, for example, to quickly analyze the uses of an alloca,
- /// global variable, or function argument.
- ///
- /// FIXME: Provide a variant which doesn't track offsets and is cheaper.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_ANALYSIS_PTRUSEVISITOR_H
- #define LLVM_ANALYSIS_PTRUSEVISITOR_H
- #include "llvm/ADT/APInt.h"
- #include "llvm/ADT/PointerIntPair.h"
- #include "llvm/ADT/SmallPtrSet.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/IR/DataLayout.h"
- #include "llvm/IR/DerivedTypes.h"
- #include "llvm/IR/InstVisitor.h"
- #include "llvm/IR/Instruction.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/IntrinsicInst.h"
- #include "llvm/IR/Intrinsics.h"
- #include "llvm/IR/Type.h"
- #include "llvm/IR/Use.h"
- #include "llvm/IR/User.h"
- #include "llvm/Support/Casting.h"
- #include <algorithm>
- #include <cassert>
- #include <type_traits>
- namespace llvm {
- namespace detail {
- /// Implementation of non-dependent functionality for \c PtrUseVisitor.
- ///
- /// See \c PtrUseVisitor for the public interface and detailed comments about
- /// usage. This class is just a helper base class which is not templated and
- /// contains all common code to be shared between different instantiations of
- /// PtrUseVisitor.
- class PtrUseVisitorBase {
- public:
- /// This class provides information about the result of a visit.
- ///
- /// After walking all the users (recursively) of a pointer, the basic
- /// infrastructure records some commonly useful information such as escape
- /// analysis and whether the visit completed or aborted early.
- class PtrInfo {
- public:
- PtrInfo() : AbortedInfo(nullptr, false), EscapedInfo(nullptr, false) {}
- /// Reset the pointer info, clearing all state.
- void reset() {
- AbortedInfo.setPointer(nullptr);
- AbortedInfo.setInt(false);
- EscapedInfo.setPointer(nullptr);
- EscapedInfo.setInt(false);
- }
- /// Did we abort the visit early?
- bool isAborted() const { return AbortedInfo.getInt(); }
- /// Is the pointer escaped at some point?
- bool isEscaped() const { return EscapedInfo.getInt(); }
- /// Get the instruction causing the visit to abort.
- /// \returns a pointer to the instruction causing the abort if one is
- /// available; otherwise returns null.
- Instruction *getAbortingInst() const { return AbortedInfo.getPointer(); }
- /// Get the instruction causing the pointer to escape.
- /// \returns a pointer to the instruction which escapes the pointer if one
- /// is available; otherwise returns null.
- Instruction *getEscapingInst() const { return EscapedInfo.getPointer(); }
- /// Mark the visit as aborted. Intended for use in a void return.
- /// \param I The instruction which caused the visit to abort, if available.
- void setAborted(Instruction *I = nullptr) {
- AbortedInfo.setInt(true);
- AbortedInfo.setPointer(I);
- }
- /// Mark the pointer as escaped. Intended for use in a void return.
- /// \param I The instruction which escapes the pointer, if available.
- void setEscaped(Instruction *I = nullptr) {
- EscapedInfo.setInt(true);
- EscapedInfo.setPointer(I);
- }
- /// Mark the pointer as escaped, and the visit as aborted. Intended
- /// for use in a void return.
- /// \param I The instruction which both escapes the pointer and aborts the
- /// visit, if available.
- void setEscapedAndAborted(Instruction *I = nullptr) {
- setEscaped(I);
- setAborted(I);
- }
- private:
- PointerIntPair<Instruction *, 1, bool> AbortedInfo, EscapedInfo;
- };
- protected:
- const DataLayout &DL;
- /// \name Visitation infrastructure
- /// @{
- /// The info collected about the pointer being visited thus far.
- PtrInfo PI;
- /// A struct of the data needed to visit a particular use.
- ///
- /// This is used to maintain a worklist fo to-visit uses. This is used to
- /// make the visit be iterative rather than recursive.
- struct UseToVisit {
- using UseAndIsOffsetKnownPair = PointerIntPair<Use *, 1, bool>;
- UseAndIsOffsetKnownPair UseAndIsOffsetKnown;
- APInt Offset;
- };
- /// The worklist of to-visit uses.
- SmallVector<UseToVisit, 8> Worklist;
- /// A set of visited uses to break cycles in unreachable code.
- SmallPtrSet<Use *, 8> VisitedUses;
- /// @}
- /// \name Per-visit state
- /// This state is reset for each instruction visited.
- /// @{
- /// The use currently being visited.
- Use *U;
- /// True if we have a known constant offset for the use currently
- /// being visited.
- bool IsOffsetKnown;
- /// The constant offset of the use if that is known.
- APInt Offset;
- /// @}
- /// Note that the constructor is protected because this class must be a base
- /// class, we can't create instances directly of this class.
- PtrUseVisitorBase(const DataLayout &DL) : DL(DL) {}
- /// Enqueue the users of this instruction in the visit worklist.
- ///
- /// This will visit the users with the same offset of the current visit
- /// (including an unknown offset if that is the current state).
- void enqueueUsers(Instruction &I);
- /// Walk the operands of a GEP and adjust the offset as appropriate.
- ///
- /// This routine does the heavy lifting of the pointer walk by computing
- /// offsets and looking through GEPs.
- bool adjustOffsetForGEP(GetElementPtrInst &GEPI);
- };
- } // end namespace detail
- /// A base class for visitors over the uses of a pointer value.
- ///
- /// Once constructed, a user can call \c visit on a pointer value, and this
- /// will walk its uses and visit each instruction using an InstVisitor. It also
- /// provides visit methods which will recurse through any pointer-to-pointer
- /// transformations such as GEPs and bitcasts.
- ///
- /// During the visit, the current Use* being visited is available to the
- /// subclass, as well as the current offset from the original base pointer if
- /// known.
- ///
- /// The recursive visit of uses is accomplished with a worklist, so the only
- /// ordering guarantee is that an instruction is visited before any uses of it
- /// are visited. Note that this does *not* mean before any of its users are
- /// visited! This is because users can be visited multiple times due to
- /// multiple, different uses of pointers derived from the same base.
- ///
- /// A particular Use will only be visited once, but a User may be visited
- /// multiple times, once per Use. This visits may notably have different
- /// offsets.
- ///
- /// All visit methods on the underlying InstVisitor return a boolean. This
- /// return short-circuits the visit, stopping it immediately.
- ///
- /// FIXME: Generalize this for all values rather than just instructions.
- template <typename DerivedT>
- class PtrUseVisitor : protected InstVisitor<DerivedT>,
- public detail::PtrUseVisitorBase {
- friend class InstVisitor<DerivedT>;
- using Base = InstVisitor<DerivedT>;
- public:
- PtrUseVisitor(const DataLayout &DL) : PtrUseVisitorBase(DL) {
- static_assert(std::is_base_of<PtrUseVisitor, DerivedT>::value,
- "Must pass the derived type to this template!");
- }
- /// Recursively visit the uses of the given pointer.
- /// \returns An info struct about the pointer. See \c PtrInfo for details.
- PtrInfo visitPtr(Instruction &I) {
- // This must be a pointer type. Get an integer type suitable to hold
- // offsets on this pointer.
- // FIXME: Support a vector of pointers.
- assert(I.getType()->isPointerTy());
- IntegerType *IntIdxTy = cast<IntegerType>(DL.getIndexType(I.getType()));
- IsOffsetKnown = true;
- Offset = APInt(IntIdxTy->getBitWidth(), 0);
- PI.reset();
- // Enqueue the uses of this pointer.
- enqueueUsers(I);
- // Visit all the uses off the worklist until it is empty.
- while (!Worklist.empty()) {
- UseToVisit ToVisit = Worklist.pop_back_val();
- U = ToVisit.UseAndIsOffsetKnown.getPointer();
- IsOffsetKnown = ToVisit.UseAndIsOffsetKnown.getInt();
- if (IsOffsetKnown)
- Offset = std::move(ToVisit.Offset);
- Instruction *I = cast<Instruction>(U->getUser());
- static_cast<DerivedT*>(this)->visit(I);
- if (PI.isAborted())
- break;
- }
- return PI;
- }
- protected:
- void visitStoreInst(StoreInst &SI) {
- if (SI.getValueOperand() == U->get())
- PI.setEscaped(&SI);
- }
- void visitBitCastInst(BitCastInst &BC) {
- enqueueUsers(BC);
- }
- void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
- enqueueUsers(ASC);
- }
- void visitPtrToIntInst(PtrToIntInst &I) {
- PI.setEscaped(&I);
- }
- void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
- if (GEPI.use_empty())
- return;
- // If we can't walk the GEP, clear the offset.
- if (!adjustOffsetForGEP(GEPI)) {
- IsOffsetKnown = false;
- Offset = APInt();
- }
- // Enqueue the users now that the offset has been adjusted.
- enqueueUsers(GEPI);
- }
- // No-op intrinsics which we know don't escape the pointer to logic in
- // some other function.
- void visitDbgInfoIntrinsic(DbgInfoIntrinsic &I) {}
- void visitMemIntrinsic(MemIntrinsic &I) {}
- void visitIntrinsicInst(IntrinsicInst &II) {
- switch (II.getIntrinsicID()) {
- default:
- return Base::visitIntrinsicInst(II);
- case Intrinsic::lifetime_start:
- case Intrinsic::lifetime_end:
- return; // No-op intrinsics.
- }
- }
- // Generically, arguments to calls and invokes escape the pointer to some
- // other function. Mark that.
- void visitCallBase(CallBase &CB) {
- PI.setEscaped(&CB);
- Base::visitCallBase(CB);
- }
- };
- } // end namespace llvm
- #endif // LLVM_ANALYSIS_PTRUSEVISITOR_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|