[llvm-commits] [llvm] r169728 - in /llvm/trunk: include/llvm/Analysis/PtrUseVisitor.h lib/Analysis/CMakeLists.txt lib/Analysis/PtrUseVisitor.cpp lib/Transforms/Scalar/SROA.cpp
Duncan Sands
baldrick at free.fr
Mon Dec 10 01:28:57 PST 2012
Hi Chandler,
> Add a new visitor for walking the uses of a pointer value.
> --- llvm/trunk/include/llvm/Analysis/PtrUseVisitor.h (added)
> +++ llvm/trunk/include/llvm/Analysis/PtrUseVisitor.h Mon Dec 10 02:28:39 2012
> @@ -0,0 +1,286 @@
> +//===- PtrUseVisitor.h - InstVisitors over a pointers uses ------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +/// \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/SmallPtrSet.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/DataLayout.h"
> +#include "llvm/InstVisitor.h"
> +#include "llvm/IntrinsicInst.h"
> +#include "llvm/Support/Compiler.h"
> +#include "llvm/Support/GetElementPtrTypeIterator.h"
> +
> +namespace llvm {
> +
> +namespace detail {
> +/// \brief 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:
> + /// \brief 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(0, false), EscapedInfo(0, false) {}
> +
> + /// \brief Reset the pointer info, clearing all state.
> + void reset() {
> + AbortedInfo.setPointer(0);
> + AbortedInfo.setInt(false);
> + EscapedInfo.setPointer(0);
> + EscapedInfo.setInt(false);
> + }
> +
> + /// \brief Did we abort the visit early?
> + bool isAborted() const { return AbortedInfo.getInt(); }
Can't this just return whether the "aborted pointer" is not null?
> +
> + /// \brief Is the pointer escaped at some point?
Is the pointer escaped -> Did the pointer escape
Can't this just be a test that the "escaped pointer" is not null?
> + /// \brief 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(); }
Otherwise you could have an assertion here that if the pointer is non-null then
isAborted is true, to catch mistakes.
> +
> + /// \brief 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(); }
Likewise.
> +
> + /// \brief Mark the visit as aborted. Intended for use in a void return.
Intended for use in a void return? What does this mean? What happens if I is
used for an instruction that is not a void return?
> + /// \param I The instruction which caused the visit to abort, if available.
> + void setAborted(Instruction *I = 0) {
> + AbortedInfo.setInt(true);
> + AbortedInfo.setPointer(I);
> + }
> +
> + /// \brief Mark the pointer as escaped. Intended for use in a void return.
Likewise.
> + /// \param I The instruction which escapes the pointer, if available.
> + void setEscaped(Instruction *I = 0) {
> + EscapedInfo.setInt(true);
> + EscapedInfo.setPointer(I);
> + }
> +
> + /// \brief Mark the pointer as escaped, and the visit as aborted. Intended
> + /// for use in a void return.
Likewise.
> + /// \param I The instruction which both escapes the pointer and aborts the
> + /// visit, if available.
> + void setEscapedAndAborted(Instruction *I = 0) {
> + setEscaped(I);
> + setAborted(I);
> + }
> +
> + private:
> + PointerIntPair<Instruction *, 1, bool> AbortedInfo, EscapedInfo;
> + };
> +
> +protected:
> + const DataLayout &DL;
> +
> + /// \name Visitation infrastructure
> + /// @{
> +
> + /// \brief The info collected about the pointer being visited thus far.
> + PtrInfo PI;
> +
> + /// \brief A struct of the data needed to visit a particular use.
Bike shed: you can drop "A struct of" and just have: The data needed...
> + ///
> + /// This is used to maintain a worklist fo to-visit uses. This is used to
worklist fo -> worklist for
> + /// make the visit be iterative rather than recursive.
> + struct UseToVisit {
> + typedef PointerIntPair<Use *, 1, bool> UseAndIsOffsetKnownPair;
> + UseAndIsOffsetKnownPair UseAndIsOffsetKnown;
> + APInt Offset;
> + };
> +
> + /// \brief The worklist of to-visit uses.
> + SmallVector<UseToVisit, 8> Worklist;
> +
> + /// \brief 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.
> + /// @{
> +
> + /// \brief The use currently being visited.
> + Use *U;
> +
> + /// \brief True if we have a known constant offset for the use currently
> + /// being visited.
> + bool IsOffsetKnown;
> +
> + /// \brief 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) {}
> +
> + /// \brief 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);
> +
> + /// \brief 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
> +
> +/// \brief 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
This visits -> These visits
> +/// offsets.
> +///
> +/// All visit methods on the underlying InstVisitor return a boolean. This
> +/// return short-circuits the visit, stopping it immediately.
Short-circuits when the returned value is true, or when it is false?
> +///
> +/// 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>;
> + typedef InstVisitor<DerivedT> Base;
> +
> +public:
> + PtrUseVisitor(const DataLayout &DL) : PtrUseVisitorBase(DL) {}
> +
> + /// \brief 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 *IntPtrTy = cast<IntegerType>(DL.getIntPtrType(I.getType()));
> + IsOffsetKnown = true;
> + Offset = APInt(IntPtrTy->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 = llvm_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 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 to logic in
to to
> + // some other function.
Also, I couldn't parse this sentence. It started OK, but I got lost after the
"to to".
> + 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 visitCallSite(CallSite CS) {
> + PI.setEscaped(CS.getInstruction());
> + Base::visitCallSite(CS);
> + }
> +};
> +
> +}
> +
> +#endif
Otherwise LGTM.
Ciao, Duncan.
More information about the llvm-commits
mailing list