forked from OSchip/llvm-project
Move the capture analysis from MemoryDependencyAnalysis to a more general place
so that it can be reused in MemCpyOptimizer. This analysis is needed to remove an unnecessary memcpy when returning a struct into a local variable. rdar://11341081 PR12686 llvm-svn: 156776
This commit is contained in:
parent
f6b687e5d1
commit
a968caf8e0
|
@ -50,6 +50,7 @@ class Pass;
|
|||
class AnalysisUsage;
|
||||
class MemTransferInst;
|
||||
class MemIntrinsic;
|
||||
class DominatorTree;
|
||||
|
||||
class AliasAnalysis {
|
||||
protected:
|
||||
|
@ -462,6 +463,18 @@ public:
|
|||
virtual ModRefResult getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2);
|
||||
|
||||
/// callCapturesBefore - Return information about whether a particular call
|
||||
/// site modifies or reads the specified memory location.
|
||||
ModRefResult callCapturesBefore(const Instruction *I,
|
||||
const AliasAnalysis::Location &MemLoc,
|
||||
DominatorTree *DT);
|
||||
|
||||
/// callCapturesBefore - A convenience wrapper.
|
||||
ModRefResult callCapturesBefore(const Instruction *I, const Value *P,
|
||||
uint64_t Size, DominatorTree *DT) {
|
||||
return callCapturesBefore(I, Location(P, Size), DT);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Higher level methods for querying mod/ref information.
|
||||
///
|
||||
|
|
|
@ -431,9 +431,6 @@ namespace llvm {
|
|||
|
||||
void RemoveCachedNonLocalPointerDependencies(ValueIsLoadPair P);
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
getModRefInfo(const Instruction *Inst, const AliasAnalysis::Location &Loc);
|
||||
|
||||
/// verifyRemoved - Verify that the specified instruction does not occur
|
||||
/// in our internal data structures.
|
||||
void verifyRemoved(Instruction *Inst) const;
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/CaptureTracking.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/BasicBlock.h"
|
||||
#include "llvm/Function.h"
|
||||
|
@ -356,6 +359,86 @@ AliasAnalysis::getModRefInfo(const AtomicRMWInst *RMW, const Location &Loc) {
|
|||
return ModRef;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Only find pointer captures which happen before the given instruction. Uses
|
||||
/// the dominator tree to determine whether one instruction is before another.
|
||||
struct CapturesBefore : public CaptureTracker {
|
||||
CapturesBefore(const Instruction *I, DominatorTree *DT)
|
||||
: BeforeHere(I), DT(DT), Captured(false) {}
|
||||
|
||||
void tooManyUses() { Captured = true; }
|
||||
|
||||
bool shouldExplore(Use *U) {
|
||||
Instruction *I = cast<Instruction>(U->getUser());
|
||||
BasicBlock *BB = I->getParent();
|
||||
if (BeforeHere != I &&
|
||||
(!DT->isReachableFromEntry(BB) || DT->dominates(BeforeHere, I)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool captured(Use *U) {
|
||||
Instruction *I = cast<Instruction>(U->getUser());
|
||||
BasicBlock *BB = I->getParent();
|
||||
if (BeforeHere != I &&
|
||||
(!DT->isReachableFromEntry(BB) || DT->dominates(BeforeHere, I)))
|
||||
return false;
|
||||
Captured = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const Instruction *BeforeHere;
|
||||
DominatorTree *DT;
|
||||
|
||||
bool Captured;
|
||||
};
|
||||
}
|
||||
|
||||
// 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.
|
||||
AliasAnalysis::ModRefResult
|
||||
AliasAnalysis::callCapturesBefore(const Instruction *I,
|
||||
const AliasAnalysis::Location &MemLoc,
|
||||
DominatorTree *DT) {
|
||||
if (!DT || !TD) return AliasAnalysis::ModRef;
|
||||
|
||||
const Value *Object = GetUnderlyingObject(MemLoc.Ptr, TD);
|
||||
if (!isIdentifiedObject(Object) || isa<GlobalValue>(Object) ||
|
||||
isa<Constant>(Object))
|
||||
return AliasAnalysis::ModRef;
|
||||
|
||||
ImmutableCallSite CS(I);
|
||||
if (!CS.getInstruction() || CS.getInstruction() == Object)
|
||||
return AliasAnalysis::ModRef;
|
||||
|
||||
CapturesBefore CB(I, DT);
|
||||
llvm::PointerMayBeCaptured(Object, &CB);
|
||||
if (CB.Captured)
|
||||
return AliasAnalysis::ModRef;
|
||||
|
||||
unsigned ArgNo = 0;
|
||||
for (ImmutableCallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
|
||||
CI != CE; ++CI, ++ArgNo) {
|
||||
// Only look at the no-capture or byval pointer arguments. If this
|
||||
// pointer were passed to arguments that were neither of these, then it
|
||||
// couldn't be no-capture.
|
||||
if (!(*CI)->getType()->isPointerTy() ||
|
||||
(!CS.doesNotCapture(ArgNo) && !CS.isByValArgument(ArgNo)))
|
||||
continue;
|
||||
|
||||
// If this is a no-capture pointer argument, see if we can tell that it
|
||||
// is impossible to alias the pointer we're checking. If not, we have to
|
||||
// assume that the call could touch the pointer, even though it doesn't
|
||||
// escape.
|
||||
if (!isNoAlias(AliasAnalysis::Location(*CI),
|
||||
AliasAnalysis::Location(Object))) {
|
||||
return AliasAnalysis::ModRef;
|
||||
}
|
||||
}
|
||||
return AliasAnalysis::NoModRef;
|
||||
}
|
||||
|
||||
// AliasAnalysis destructor: DO NOT move this to the header file for
|
||||
// AliasAnalysis or else clients of the AliasAnalysis class may not depend on
|
||||
|
|
|
@ -16,13 +16,11 @@
|
|||
|
||||
#define DEBUG_TYPE "memdep"
|
||||
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/IntrinsicInst.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/CaptureTracking.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||
|
@ -339,88 +337,6 @@ getLoadLoadClobberFullWidthSize(const Value *MemLocBase, int64_t MemLocOffs,
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Only find pointer captures which happen before the given instruction. Uses
|
||||
/// the dominator tree to determine whether one instruction is before another.
|
||||
struct CapturesBefore : public CaptureTracker {
|
||||
CapturesBefore(const Instruction *I, DominatorTree *DT)
|
||||
: BeforeHere(I), DT(DT), Captured(false) {}
|
||||
|
||||
void tooManyUses() { Captured = true; }
|
||||
|
||||
bool shouldExplore(Use *U) {
|
||||
Instruction *I = cast<Instruction>(U->getUser());
|
||||
BasicBlock *BB = I->getParent();
|
||||
if (BeforeHere != I &&
|
||||
(!DT->isReachableFromEntry(BB) || DT->dominates(BeforeHere, I)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool captured(Use *U) {
|
||||
Instruction *I = cast<Instruction>(U->getUser());
|
||||
BasicBlock *BB = I->getParent();
|
||||
if (BeforeHere != I &&
|
||||
(!DT->isReachableFromEntry(BB) || DT->dominates(BeforeHere, I)))
|
||||
return false;
|
||||
Captured = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const Instruction *BeforeHere;
|
||||
DominatorTree *DT;
|
||||
|
||||
bool Captured;
|
||||
};
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
MemoryDependenceAnalysis::getModRefInfo(const Instruction *Inst,
|
||||
const AliasAnalysis::Location &MemLoc) {
|
||||
AliasAnalysis::ModRefResult MR = AA->getModRefInfo(Inst, MemLoc);
|
||||
if (MR != AliasAnalysis::ModRef) return MR;
|
||||
|
||||
// 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.
|
||||
if (!DT) return AliasAnalysis::ModRef;
|
||||
const Value *Object = GetUnderlyingObject(MemLoc.Ptr, TD);
|
||||
if (!isIdentifiedObject(Object) || isa<GlobalValue>(Object) ||
|
||||
isa<Constant>(Object))
|
||||
return AliasAnalysis::ModRef;
|
||||
|
||||
ImmutableCallSite CS(Inst);
|
||||
if (!CS.getInstruction() || CS.getInstruction() == Object)
|
||||
return AliasAnalysis::ModRef;
|
||||
|
||||
CapturesBefore CB(Inst, DT);
|
||||
llvm::PointerMayBeCaptured(Object, &CB);
|
||||
if (CB.Captured)
|
||||
return AliasAnalysis::ModRef;
|
||||
|
||||
unsigned ArgNo = 0;
|
||||
for (ImmutableCallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
|
||||
CI != CE; ++CI, ++ArgNo) {
|
||||
// Only look at the no-capture or byval pointer arguments. If this
|
||||
// pointer were passed to arguments that were neither of these, then it
|
||||
// couldn't be no-capture.
|
||||
if (!(*CI)->getType()->isPointerTy() ||
|
||||
(!CS.doesNotCapture(ArgNo) && !CS.isByValArgument(ArgNo)))
|
||||
continue;
|
||||
|
||||
// If this is a no-capture pointer argument, see if we can tell that it
|
||||
// is impossible to alias the pointer we're checking. If not, we have to
|
||||
// assume that the call could touch the pointer, even though it doesn't
|
||||
// escape.
|
||||
if (!AA->isNoAlias(AliasAnalysis::Location(*CI),
|
||||
AliasAnalysis::Location(Object))) {
|
||||
return AliasAnalysis::ModRef;
|
||||
}
|
||||
}
|
||||
return AliasAnalysis::NoModRef;
|
||||
}
|
||||
|
||||
/// getPointerDependencyFrom - Return the instruction on which a memory
|
||||
/// location depends. If isLoad is true, this routine ignores may-aliases with
|
||||
/// read-only operations. If isLoad is false, this routine ignores may-aliases
|
||||
|
@ -568,7 +484,11 @@ getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad,
|
|||
}
|
||||
|
||||
// See if this instruction (e.g. a call or vaarg) mod/ref's the pointer.
|
||||
switch (getModRefInfo(Inst, MemLoc)) {
|
||||
AliasAnalysis::ModRefResult MR = AA->getModRefInfo(Inst, MemLoc);
|
||||
// If necessary, perform additional analysis.
|
||||
if (MR == AliasAnalysis::ModRef)
|
||||
MR = AA->callCapturesBefore(Inst, MemLoc, DT);
|
||||
switch (MR) {
|
||||
case AliasAnalysis::NoModRef:
|
||||
// If the call has no effect on the queried pointer, just ignore it.
|
||||
continue;
|
||||
|
|
|
@ -662,7 +662,11 @@ bool MemCpyOpt::performCallSlotOptzn(Instruction *cpy,
|
|||
// the use analysis, we also need to know that it does not sneakily
|
||||
// access dest. We rely on AA to figure this out for us.
|
||||
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
|
||||
if (AA.getModRefInfo(C, cpyDest, srcSize) != AliasAnalysis::NoModRef)
|
||||
AliasAnalysis::ModRefResult MR = AA.getModRefInfo(C, cpyDest, srcSize);
|
||||
// If necessary, perform additional analysis.
|
||||
if (MR != AliasAnalysis::NoModRef)
|
||||
MR = AA.callCapturesBefore(C, cpyDest, srcSize, &DT);
|
||||
if (MR != AliasAnalysis::NoModRef)
|
||||
return false;
|
||||
|
||||
// All the checks have passed, so do the transformation.
|
||||
|
|
|
@ -148,3 +148,25 @@ define void @test8() {
|
|||
}
|
||||
|
||||
declare noalias i8* @malloc(i32)
|
||||
|
||||
; rdar://11341081
|
||||
%struct.big = type { [50 x i32] }
|
||||
|
||||
define void @test9() nounwind uwtable ssp {
|
||||
entry:
|
||||
; CHECK: test9
|
||||
; CHECK: f1
|
||||
; CHECK-NOT: memcpy
|
||||
; CHECK: f2
|
||||
%b = alloca %struct.big, align 4
|
||||
%tmp = alloca %struct.big, align 4
|
||||
call void @f1(%struct.big* sret %tmp)
|
||||
%0 = bitcast %struct.big* %b to i8*
|
||||
%1 = bitcast %struct.big* %tmp to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 200, i32 4, i1 false)
|
||||
call void @f2(%struct.big* %b)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @f1(%struct.big* sret)
|
||||
declare void @f2(%struct.big*)
|
||||
|
|
Loading…
Reference in New Issue