Skip to content

Commit

Permalink
[CaptureTracking] Ignore ephemeral values when determining pointer es…
Browse files Browse the repository at this point in the history
…capeness

Ephemeral values cannot cause a pointer to escape.

No change in compile time:
https://llvm-compile-time-tracker.com/compare.php?from=4371710085ba1c376a094948b806ddd3b88319de&to=c5ddbcc4866f38026737762ee8d7b9b00395d4f4&stat=instructions

This partially fixes some regressions caused by more calls to `__builtin_assume` (D122397).

Reviewed By: asbirlea

Differential Revision: https://reviews.llvm.org/D123162
  • Loading branch information
aeubanks committed Apr 7, 2022
1 parent 26d974d commit 17fdacc
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
7 changes: 7 additions & 0 deletions llvm/include/llvm/Analysis/CaptureTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace llvm {
class DominatorTree;
class LoopInfo;
class Function;
template <typename T> class SmallPtrSetImpl;

/// getDefaultMaxUsesToExploreForCaptureTracking - Return default value of
/// the maximal number of uses to explore before giving up. It is used by
Expand All @@ -41,8 +42,14 @@ namespace llvm {
/// MaxUsesToExplore specifies how many uses the analysis should explore for
/// one value before giving up due too "too many uses". If MaxUsesToExplore
/// is zero, a default value is assumed.
bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures,
bool StoreCaptures, unsigned MaxUsesToExplore = 0);

/// Variant of the above function which accepts a set of Values that are
/// ephemeral and cannot cause pointers to escape.
bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures,
bool StoreCaptures,
const SmallPtrSetImpl<const Value *> &EphValues,
unsigned MaxUsesToExplore = 0);

/// PointerMayBeCapturedBefore - Return true if this pointer value may be
Expand Down
28 changes: 23 additions & 5 deletions llvm/lib/Analysis/CaptureTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
Expand Down Expand Up @@ -74,19 +75,26 @@ bool CaptureTracker::isDereferenceableOrNull(Value *O, const DataLayout &DL) {

namespace {
struct SimpleCaptureTracker : public CaptureTracker {
explicit SimpleCaptureTracker(bool ReturnCaptures)
: ReturnCaptures(ReturnCaptures) {}
explicit SimpleCaptureTracker(

const SmallPtrSetImpl<const Value *> &EphValues, bool ReturnCaptures)
: EphValues(EphValues), ReturnCaptures(ReturnCaptures) {}

void tooManyUses() override { Captured = true; }

bool captured(const Use *U) override {
if (isa<ReturnInst>(U->getUser()) && !ReturnCaptures)
return false;

if (EphValues.contains(U->getUser()))
return false;

Captured = true;
return true;
}

const SmallPtrSetImpl<const Value *> &EphValues;

bool ReturnCaptures;

bool Captured = false;
Expand Down Expand Up @@ -212,8 +220,18 @@ namespace {
/// 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.
bool llvm::PointerMayBeCaptured(const Value *V,
bool ReturnCaptures, bool StoreCaptures,
bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures,
bool StoreCaptures, unsigned MaxUsesToExplore) {
SmallPtrSet<const Value *, 1> Empty;
return PointerMayBeCaptured(V, ReturnCaptures, StoreCaptures, Empty,
MaxUsesToExplore);
}

/// Variant of the above function which accepts a set of Values that are
/// ephemeral and cannot cause pointers to escape.
bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures,
bool StoreCaptures,
const SmallPtrSetImpl<const Value *> &EphValues,
unsigned MaxUsesToExplore) {
assert(!isa<GlobalValue>(V) &&
"It doesn't make sense to ask whether a global is captured.");
Expand All @@ -224,7 +242,7 @@ bool llvm::PointerMayBeCaptured(const Value *V,
// take advantage of this.
(void)StoreCaptures;

SimpleCaptureTracker SCT(ReturnCaptures);
SimpleCaptureTracker SCT(EphValues, ReturnCaptures);
PointerMayBeCaptured(V, &SCT, MaxUsesToExplore);
if (SCT.Captured)
++NumCaptured;
Expand Down
27 changes: 20 additions & 7 deletions llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
Expand Down Expand Up @@ -762,6 +764,9 @@ struct DSEState {
// Post-order numbers for each basic block. Used to figure out if memory
// accesses are executed before another access.
DenseMap<BasicBlock *, unsigned> PostOrderNumbers;
// Values that are only used with assumes. Used to refine pointer escape
// analysis.
SmallPtrSet<const Value *, 32> EphValues;

/// Keep track of instructions (partly) overlapping with killing MemoryDefs per
/// basic block.
Expand All @@ -776,8 +781,8 @@ struct DSEState {
DSEState &operator=(const DSEState &) = delete;

DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT,
PostDominatorTree &PDT, const TargetLibraryInfo &TLI,
const LoopInfo &LI)
PostDominatorTree &PDT, AssumptionCache &AC,
const TargetLibraryInfo &TLI, const LoopInfo &LI)
: F(F), AA(AA), EI(DT, LI), BatchAA(AA, &EI), MSSA(MSSA), DT(DT),
PDT(PDT), TLI(TLI), DL(F.getParent()->getDataLayout()), LI(LI) {
// Collect blocks with throwing instructions not modeled in MemorySSA and
Expand Down Expand Up @@ -809,6 +814,8 @@ struct DSEState {
AnyUnreachableExit = any_of(PDT.roots(), [](const BasicBlock *E) {
return isa<UnreachableInst>(E->getTerminator());
});

CodeMetrics::collectEphemeralValues(&F, &AC, EphValues);
}

/// Return 'OW_Complete' if a store to the 'KillingLoc' location (by \p
Expand Down Expand Up @@ -955,7 +962,7 @@ struct DSEState {
if (!isInvisibleToCallerOnUnwind(V)) {
I.first->second = false;
} else if (isNoAliasCall(V)) {
I.first->second = !PointerMayBeCaptured(V, true, false);
I.first->second = !PointerMayBeCaptured(V, true, false, EphValues);
}
}
return I.first->second;
Expand All @@ -974,7 +981,7 @@ struct DSEState {
// with the killing MemoryDef. But we refrain from doing so for now to
// limit compile-time and this does not cause any changes to the number
// of stores removed on a large test set in practice.
I.first->second = PointerMayBeCaptured(V, false, true);
I.first->second = PointerMayBeCaptured(V, false, true, EphValues);
return !I.first->second;
}

Expand Down Expand Up @@ -1929,12 +1936,13 @@ struct DSEState {

static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
DominatorTree &DT, PostDominatorTree &PDT,
AssumptionCache &AC,
const TargetLibraryInfo &TLI,
const LoopInfo &LI) {
bool MadeChange = false;

MSSA.ensureOptimizedUses();
DSEState State(F, AA, MSSA, DT, PDT, TLI, LI);
DSEState State(F, AA, MSSA, DT, PDT, AC, TLI, LI);
// For each store:
for (unsigned I = 0; I < State.MemDefs.size(); I++) {
MemoryDef *KillingDef = State.MemDefs[I];
Expand Down Expand Up @@ -2114,9 +2122,10 @@ PreservedAnalyses DSEPass::run(Function &F, FunctionAnalysisManager &AM) {
DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
MemorySSA &MSSA = AM.getResult<MemorySSAAnalysis>(F).getMSSA();
PostDominatorTree &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
LoopInfo &LI = AM.getResult<LoopAnalysis>(F);

bool Changed = eliminateDeadStores(F, AA, MSSA, DT, PDT, TLI, LI);
bool Changed = eliminateDeadStores(F, AA, MSSA, DT, PDT, AC, TLI, LI);

#ifdef LLVM_ENABLE_STATS
if (AreStatisticsEnabled())
Expand Down Expand Up @@ -2156,9 +2165,11 @@ class DSELegacyPass : public FunctionPass {
MemorySSA &MSSA = getAnalysis<MemorySSAWrapperPass>().getMSSA();
PostDominatorTree &PDT =
getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
AssumptionCache &AC =
getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();

bool Changed = eliminateDeadStores(F, AA, MSSA, DT, PDT, TLI, LI);
bool Changed = eliminateDeadStores(F, AA, MSSA, DT, PDT, AC, TLI, LI);

#ifdef LLVM_ENABLE_STATS
if (AreStatisticsEnabled())
Expand All @@ -2182,6 +2193,7 @@ class DSELegacyPass : public FunctionPass {
AU.addPreserved<MemorySSAWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
AU.addPreserved<LoopInfoWrapperPass>();
AU.addRequired<AssumptionCacheTracker>();
}
};

Expand All @@ -2199,6 +2211,7 @@ INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_END(DSELegacyPass, "dse", "Dead Store Elimination", false,
false)

Expand Down
1 change: 0 additions & 1 deletion llvm/test/Transforms/DeadStoreElimination/assume.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ define void @f() {
; CHECK-NEXT: [[TMP1:%.*]] = call noalias i8* @_Znwm(i64 32)
; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i8* [[TMP1]], @global
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP2]])
; CHECK-NEXT: store i8 0, i8* [[TMP1]], align 1
; CHECK-NEXT: ret void
;
%tmp1 = call noalias i8* @_Znwm(i64 32)
Expand Down

0 comments on commit 17fdacc

Please sign in to comment.