mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-04 17:58:22 +00:00
[CaptureTracker] Provide an ordered basic block to PointerMayBeCapturedBefore
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243750 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
289b5e7f39
commit
8fea35acad
@ -55,6 +55,7 @@ class AnalysisUsage;
|
||||
class MemTransferInst;
|
||||
class MemIntrinsic;
|
||||
class DominatorTree;
|
||||
class OrderedBasicBlock;
|
||||
|
||||
/// The possible results of an alias query.
|
||||
///
|
||||
@ -501,16 +502,19 @@ public:
|
||||
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);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
66
include/llvm/Analysis/OrderedBasicBlock.h
Normal file
66
include/llvm/Analysis/OrderedBasicBlock.h
Normal file
@ -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
|
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
@ -45,6 +45,7 @@ add_llvm_library(LLVMAnalysis
|
||||
MemoryLocation.cpp
|
||||
ModuleDebugInfoPrinter.cpp
|
||||
NoAliasAnalysis.cpp
|
||||
OrderedBasicBlock.cpp
|
||||
PHITransAddr.cpp
|
||||
PostDominators.cpp
|
||||
PtrUseVisitor.cpp
|
||||
|
@ -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"
|
||||
@ -52,63 +53,6 @@ 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
|
||||
@ -116,8 +60,8 @@ namespace {
|
||||
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; }
|
||||
@ -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.
|
||||
@ -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
|
||||
@ -196,7 +140,7 @@ namespace {
|
||||
return true;
|
||||
}
|
||||
|
||||
NumberedInstCache LocalInstCache;
|
||||
OrderedBasicBlock *OrderedBB;
|
||||
const Instruction *BeforeHere;
|
||||
DominatorTree *DT;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
@ -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;
|
||||
@ -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.
|
||||
|
85
lib/Analysis/OrderedBasicBlock.cpp
Normal file
85
lib/Analysis/OrderedBasicBlock.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
//===- OrderedBasicBlock.cpp --------------------------------- -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/OrderedBasicBlock.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
using namespace llvm;
|
||||
|
||||
OrderedBasicBlock::OrderedBasicBlock(const BasicBlock *BasicB)
|
||||
: NextInstPos(0), BB(BasicB) {
|
||||
LastInstFound = BB->end();
|
||||
}
|
||||
|
||||
/// \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 OrderedBasicBlock::comesBefore(const Instruction *A,
|
||||
const Instruction *B) {
|
||||
const Instruction *Inst = nullptr;
|
||||
assert(!(LastInstFound == BB->end() && NextInstPos != 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 (; II != IE; ++II) {
|
||||
Inst = cast<Instruction>(II);
|
||||
NumberedInsts[Inst] = NextInstPos++;
|
||||
if (Inst == A || Inst == B)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(II != IE && "Instruction not found?");
|
||||
assert((Inst == A || Inst == B) && "Should find A or B");
|
||||
LastInstFound = II;
|
||||
return Inst == A;
|
||||
}
|
||||
|
||||
/// \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 OrderedBasicBlock::dominates(const Instruction *A, const Instruction *B) {
|
||||
assert(A->getParent() == B->getParent() &&
|
||||
"Instructions must be in the same basic block!");
|
||||
|
||||
// First we lookup the instructions. If they don't exist, lookup will give us
|
||||
// back ::end(). If they both exist, we compare the numbers. Otherwise, if NA
|
||||
// exists and NB doesn't, it means NA must come before NB because we would
|
||||
// have numbered NB as well if it didn't. The same is true for NB. If it
|
||||
// exists, but NA does not, NA must come after it. If neither exist, we need
|
||||
// to number the block and cache the results (by calling comesBefore).
|
||||
auto NAI = NumberedInsts.find(A);
|
||||
auto NBI = NumberedInsts.find(B);
|
||||
if (NAI != NumberedInsts.end() && NBI != NumberedInsts.end())
|
||||
return NAI->second < NBI->second;
|
||||
if (NAI != NumberedInsts.end())
|
||||
return true;
|
||||
if (NBI != NumberedInsts.end())
|
||||
return false;
|
||||
|
||||
return comesBefore(A, B);
|
||||
}
|
Loading…
Reference in New Issue
Block a user