//===- 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/DerivedTypes.h"
 
#include "llvm/IR/InstVisitor.h"
 
#include "llvm/IR/IntrinsicInst.h"
 
#include <cassert>
 
#include <type_traits>
 
 
 
namespace llvm {
 
class DataLayout;
 
class Use;
 
 
 
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