Skip to content

Commit

Permalink
[CaptureTracker] Provide an ordered basic block to PointerMayBeCaptur…
Browse files Browse the repository at this point in the history
…edBefore

This patch is a follow up from r240560 and is a step further into
mitigating the compile time performance issues in CaptureTracker.

By providing the CaptureTracker with a "cached ordered basic block"
instead of computing it every time, MemDepAnalysis can use this cache
throughout its calls to AA->callCapturesBefore, avoiding to recompute it
for every scanned instruction. In the same testcase used in r240560,
compile time is reduced from 2min to 30s.

This also fixes PR22348.

rdar://problem/19230319
Differential Revision: http://reviews.llvm.org/D11364

llvm-svn: 243750
  • Loading branch information
bcardosolopes committed Jul 31, 2015
1 parent 8b559ec commit dfc1d96
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 81 deletions.
18 changes: 11 additions & 7 deletions llvm/include/llvm/Analysis/AliasAnalysis.h
Expand Up @@ -55,6 +55,7 @@ class AnalysisUsage;
class MemTransferInst;
class MemIntrinsic;
class DominatorTree;
class OrderedBasicBlock;

/// The possible results of an alias query.
///
Expand Down Expand Up @@ -501,16 +502,19 @@ class AliasAnalysis {
virtual ModRefInfo getModRefInfo(ImmutableCallSite CS1,
ImmutableCallSite CS2);

/// Return information about whether a particular call site modifies or reads
/// the specified memory location.
/// \brief Return information about whether a particular call site modifies
/// or reads the specified memory location \p MemLoc before instruction \p I
/// in a BasicBlock. A ordered basic block \p OBB can be used to speed up
/// instruction ordering queries inside the BasicBlock containing \p I.
ModRefInfo callCapturesBefore(const Instruction *I,
const MemoryLocation &MemLoc,
DominatorTree *DT);
const MemoryLocation &MemLoc, DominatorTree *DT,
OrderedBasicBlock *OBB = nullptr);

/// A convenience wrapper to synthesize a memory location.
/// \brief A convenience wrapper to synthesize a memory location.
ModRefInfo callCapturesBefore(const Instruction *I, const Value *P,
uint64_t Size, DominatorTree *DT) {
return callCapturesBefore(I, MemoryLocation(P, Size), DT);
uint64_t Size, DominatorTree *DT,
OrderedBasicBlock *OBB = nullptr) {
return callCapturesBefore(I, MemoryLocation(P, Size), DT, OBB);
}

/// @}
Expand Down
7 changes: 5 additions & 2 deletions llvm/include/llvm/Analysis/CaptureTracking.h
Expand Up @@ -20,6 +20,7 @@ namespace llvm {
class Use;
class Instruction;
class DominatorTree;
class OrderedBasicBlock;

/// PointerMayBeCaptured - Return true if this pointer value may be captured
/// by the enclosing function (which is required to exist). This routine can
Expand All @@ -41,10 +42,12 @@ namespace llvm {
/// it or not. The boolean StoreCaptures specified whether storing the value
/// (or part of it) into memory anywhere automatically counts as capturing it
/// or not. Captures by the provided instruction are considered if the
/// final parameter is true.
/// final parameter is true. An ordered basic block in \p OBB could be used
/// to speed up capture-tracker queries.
bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
bool StoreCaptures, const Instruction *I,
DominatorTree *DT, bool IncludeI = false);
DominatorTree *DT, bool IncludeI = false,
OrderedBasicBlock *OBB = nullptr);

/// This callback is used in conjunction with PointerMayBeCaptured. In
/// addition to the interface here, you'll need to provide your own getters
Expand Down
66 changes: 66 additions & 0 deletions llvm/include/llvm/Analysis/OrderedBasicBlock.h
@@ -0,0 +1,66 @@
//===- llvm/Analysis/OrderedBasicBlock.h --------------------- -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the OrderedBasicBlock class. OrderedBasicBlock maintains
// an interface where clients can query if one instruction comes before another
// in a BasicBlock. Since BasicBlock currently lacks a reliable way to query
// relative position between instructions one can use OrderedBasicBlock to do
// such queries. OrderedBasicBlock is lazily built on a source BasicBlock and
// maintains an internal Instruction -> Position map. A OrderedBasicBlock
// instance should be discarded whenever the source BasicBlock changes.
//
// It's currently used by the CaptureTracker in order to find relative
// positions of a pair of instructions inside a BasicBlock.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_ORDEREDBASICBLOCK_H
#define LLVM_ANALYSIS_ORDEREDBASICBLOCK_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/BasicBlock.h"

namespace llvm {

class Instruction;
class BasicBlock;

class OrderedBasicBlock {
private:
/// \brief Map a instruction to its position in a BasicBlock.
SmallDenseMap<const Instruction *, unsigned, 32> NumberedInsts;

/// \brief Keep track of last instruction inserted into \p NumberedInsts.
/// It speeds up queries for uncached instructions by providing a start point
/// for new queries in OrderedBasicBlock::comesBefore.
BasicBlock::const_iterator LastInstFound;

/// \brief The position/number to tag the next instruction to be found.
unsigned NextInstPos;

/// \brief The source BasicBlock to map.
const BasicBlock *BB;

/// \brief Given no cached results, find if \p A comes before \p B in \p BB.
/// Cache and number out instruction while walking \p BB.
bool comesBefore(const Instruction *A, const Instruction *B);

public:
OrderedBasicBlock(const BasicBlock *BasicB);

/// \brief Find out whether \p A dominates \p B, meaning whether \p A
/// comes before \p B in \p BB. This is a simplification that considers
/// cached instruction positions and ignores other basic blocks, being
/// only relevant to compare relative instructions positions inside \p BB.
bool dominates(const Instruction *A, const Instruction *B);
};

} // End llvm namespace

#endif
18 changes: 12 additions & 6 deletions llvm/lib/Analysis/AliasAnalysis.cpp
Expand Up @@ -335,13 +335,18 @@ ModRefInfo AliasAnalysis::getModRefInfo(const AtomicRMWInst *RMW,
return MRI_ModRef;
}

// FIXME: this is really just shoring-up a deficiency in alias analysis.
// BasicAA isn't willing to spend linear time determining whether an alloca
// was captured before or after this particular call, while we are. However,
// with a smarter AA in place, this test is just wasting compile time.
/// \brief Return information about whether a particular call site modifies
/// or reads the specified memory location \p MemLoc before instruction \p I
/// in a BasicBlock. A ordered basic block \p OBB can be used to speed up
/// instruction-ordering queries inside the BasicBlock containing \p I.
/// FIXME: this is really just shoring-up a deficiency in alias analysis.
/// BasicAA isn't willing to spend linear time determining whether an alloca
/// was captured before or after this particular call, while we are. However,
/// with a smarter AA in place, this test is just wasting compile time.
ModRefInfo AliasAnalysis::callCapturesBefore(const Instruction *I,
const MemoryLocation &MemLoc,
DominatorTree *DT) {
DominatorTree *DT,
OrderedBasicBlock *OBB) {
if (!DT)
return MRI_ModRef;

Expand All @@ -356,7 +361,8 @@ ModRefInfo AliasAnalysis::callCapturesBefore(const Instruction *I,

if (llvm::PointerMayBeCapturedBefore(Object, /* ReturnCaptures */ true,
/* StoreCaptures */ true, I, DT,
/* include Object */ true))
/* include Object */ true,
/* OrderedBasicBlock */ OBB))
return MRI_ModRef;

unsigned ArgNo = 0;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Analysis/CMakeLists.txt
Expand Up @@ -45,6 +45,7 @@ add_llvm_library(LLVMAnalysis
MemoryLocation.cpp
ModuleDebugInfoPrinter.cpp
NoAliasAnalysis.cpp
OrderedBasicBlock.cpp
PHITransAddr.cpp
PostDominators.cpp
PtrUseVisitor.cpp
Expand Down
82 changes: 17 additions & 65 deletions llvm/lib/Analysis/CaptureTracking.cpp
Expand Up @@ -21,6 +21,7 @@
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/OrderedBasicBlock.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
Expand Down Expand Up @@ -52,72 +53,15 @@ namespace {
bool Captured;
};

struct NumberedInstCache {
SmallDenseMap<const Instruction *, unsigned, 32> NumberedInsts;
BasicBlock::const_iterator LastInstFound;
unsigned LastInstPos;
const BasicBlock *BB;

NumberedInstCache(const BasicBlock *BasicB) : LastInstPos(0), BB(BasicB) {
LastInstFound = BB->end();
}

/// \brief Find the first instruction 'A' or 'B' in 'BB'. Number out
/// instruction while walking 'BB'.
const Instruction *find(const Instruction *A, const Instruction *B) {
const Instruction *Inst = nullptr;
assert(!(LastInstFound == BB->end() && LastInstPos != 0) &&
"Instruction supposed to be in NumberedInsts");

// Start the search with the instruction found in the last lookup round.
auto II = BB->begin();
auto IE = BB->end();
if (LastInstFound != IE)
II = std::next(LastInstFound);

// Number all instructions up to the point where we find 'A' or 'B'.
for (++LastInstPos; II != IE; ++II, ++LastInstPos) {
Inst = cast<Instruction>(II);
NumberedInsts[Inst] = LastInstPos;
if (Inst == A || Inst == B)
break;
}

assert(II != IE && "Instruction not found?");
LastInstFound = II;
return Inst;
}

/// \brief Find out whether 'A' dominates 'B', meaning whether 'A'
/// comes before 'B' in 'BB'. This is a simplification that considers
/// cached instruction positions and ignores other basic blocks, being
/// only relevant to compare relative instructions positions inside 'BB'.
bool dominates(const Instruction *A, const Instruction *B) {
assert(A->getParent() == B->getParent() &&
"Instructions must be in the same basic block!");

unsigned NA = NumberedInsts.lookup(A);
unsigned NB = NumberedInsts.lookup(B);
if (NA && NB)
return NA < NB;
if (NA)
return true;
if (NB)
return false;

return A == find(A, B);
}
};

/// Only find pointer captures which happen before the given instruction. Uses
/// the dominator tree to determine whether one instruction is before another.
/// Only support the case where the Value is defined in the same basic block
/// as the given instruction and the use.
struct CapturesBefore : public CaptureTracker {

CapturesBefore(bool ReturnCaptures, const Instruction *I, DominatorTree *DT,
bool IncludeI)
: LocalInstCache(I->getParent()), BeforeHere(I), DT(DT),
bool IncludeI, OrderedBasicBlock *IC)
: OrderedBB(IC), BeforeHere(I), DT(DT),
ReturnCaptures(ReturnCaptures), IncludeI(IncludeI), Captured(false) {}

void tooManyUses() override { Captured = true; }
Expand All @@ -131,7 +75,7 @@ namespace {

// Compute the case where both instructions are inside the same basic
// block. Since instructions in the same BB as BeforeHere are numbered in
// 'LocalInstCache', avoid using 'dominates' and 'isPotentiallyReachable'
// 'OrderedBB', avoid using 'dominates' and 'isPotentiallyReachable'
// which are very expensive for large basic blocks.
if (BB == BeforeHere->getParent()) {
// 'I' dominates 'BeforeHere' => not safe to prune.
Expand All @@ -142,7 +86,7 @@ namespace {
// UseBB == BB, avoid pruning.
if (isa<InvokeInst>(BeforeHere) || isa<PHINode>(I) || I == BeforeHere)
return false;
if (!LocalInstCache.dominates(BeforeHere, I))
if (!OrderedBB->dominates(BeforeHere, I))
return false;

// 'BeforeHere' comes before 'I', it's safe to prune if we also
Expand Down Expand Up @@ -196,7 +140,7 @@ namespace {
return true;
}

NumberedInstCache LocalInstCache;
OrderedBasicBlock *OrderedBB;
const Instruction *BeforeHere;
DominatorTree *DT;

Expand Down Expand Up @@ -238,21 +182,29 @@ bool llvm::PointerMayBeCaptured(const Value *V,
/// returning the value (or part of it) from the function counts as capturing
/// it or not. The boolean StoreCaptures specified whether storing the value
/// (or part of it) into memory anywhere automatically counts as capturing it
/// or not.
/// or not. A ordered basic block \p OBB can be used in order to speed up
/// queries about relative order among instructions in the same basic block.
bool llvm::PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
bool StoreCaptures, const Instruction *I,
DominatorTree *DT, bool IncludeI) {
DominatorTree *DT, bool IncludeI,
OrderedBasicBlock *OBB) {
assert(!isa<GlobalValue>(V) &&
"It doesn't make sense to ask whether a global is captured.");
bool UseNewOBB = OBB == nullptr;

if (!DT)
return PointerMayBeCaptured(V, ReturnCaptures, StoreCaptures);
if (UseNewOBB)
OBB = new OrderedBasicBlock(I->getParent());

// TODO: See comment in PointerMayBeCaptured regarding what could be done
// with StoreCaptures.

CapturesBefore CB(ReturnCaptures, I, DT, IncludeI);
CapturesBefore CB(ReturnCaptures, I, DT, IncludeI, OBB);
PointerMayBeCaptured(V, &CB);

if (UseNewOBB)
delete OBB;
return CB.Captured;
}

Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
Expand Up @@ -22,6 +22,7 @@
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/PHITransAddr.h"
#include "llvm/Analysis/OrderedBasicBlock.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
Expand Down Expand Up @@ -420,6 +421,12 @@ MemDepResult MemoryDependenceAnalysis::getPointerDependencyFrom(

const DataLayout &DL = BB->getModule()->getDataLayout();

// Create a numbered basic block to lazily compute and cache instruction
// positions inside a BB. This is used to provide fast queries for relative
// position between two instructions in a BB and can be used by
// AliasAnalysis::callCapturesBefore.
OrderedBasicBlock OBB(BB);

// Walk backwards through the basic block, looking for dependencies.
while (ScanIt != BB->begin()) {
Instruction *Inst = --ScanIt;
Expand Down Expand Up @@ -623,7 +630,7 @@ MemDepResult MemoryDependenceAnalysis::getPointerDependencyFrom(
ModRefInfo MR = AA->getModRefInfo(Inst, MemLoc);
// If necessary, perform additional analysis.
if (MR == MRI_ModRef)
MR = AA->callCapturesBefore(Inst, MemLoc, DT);
MR = AA->callCapturesBefore(Inst, MemLoc, DT, &OBB);
switch (MR) {
case MRI_NoModRef:
// If the call has no effect on the queried pointer, just ignore it.
Expand Down

0 comments on commit dfc1d96

Please sign in to comment.