Skip to content

Commit

Permalink
Revert "[CaptureTracking] Ignore ephemeral values when determining po… (
Browse files Browse the repository at this point in the history
#71066)

Unfortunately the commit (D123162) introduced a mis-compile
(#70547), which wasn't fixed
by the alternative fix (c0de28b)

I think as long as the call considered as ephemeral is not removed, we
need to be conservative. To address the correctness issue quickly, I
think we should revert the patch (as this patch does, it doens't revert
cleanly)

This reverts commit 17fdacc.

Fixes #70547
  • Loading branch information
fhahn authored Nov 2, 2023
1 parent 29fd9ba commit fd95f39
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 72 deletions.
7 changes: 2 additions & 5 deletions llvm/include/llvm/Analysis/AliasAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,9 @@ class EarliestEscapeInfo final : public CaptureInfo {
/// This is used for cache invalidation purposes.
DenseMap<Instruction *, TinyPtrVector<const Value *>> Inst2Obj;

const SmallPtrSetImpl<const Value *> *EphValues;

public:
EarliestEscapeInfo(DominatorTree &DT, const LoopInfo *LI = nullptr,
const SmallPtrSetImpl<const Value *> *EphValues = nullptr)
: DT(DT), LI(LI), EphValues(EphValues) {}
EarliestEscapeInfo(DominatorTree &DT, const LoopInfo *LI = nullptr)
: DT(DT), LI(LI) {}

bool isNotCapturedBeforeOrAt(const Value *Object,
const Instruction *I) override;
Expand Down
17 changes: 4 additions & 13 deletions llvm/include/llvm/Analysis/CaptureTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ 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 @@ -45,13 +44,6 @@ namespace llvm {
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
/// captured by the enclosing function (which is required to exist). If a
/// DominatorTree is provided, only captures which happen before the given
Expand Down Expand Up @@ -80,11 +72,10 @@ namespace llvm {
// nullptr is returned. Note that the caller of the function has to ensure
// that the instruction the result value is compared against is not in a
// cycle.
Instruction *
FindEarliestCapture(const Value *V, Function &F, bool ReturnCaptures,
bool StoreCaptures, const DominatorTree &DT,
const SmallPtrSetImpl<const Value *> *EphValues = nullptr,
unsigned MaxUsesToExplore = 0);
Instruction *FindEarliestCapture(const Value *V, Function &F,
bool ReturnCaptures, bool StoreCaptures,
const DominatorTree &DT,
unsigned MaxUsesToExplore = 0);

/// This callback is used in conjunction with PointerMayBeCaptured. In
/// addition to the interface here, you'll need to provide your own getters
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Analysis/BasicAliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ bool EarliestEscapeInfo::isNotCapturedBeforeOrAt(const Value *Object,
if (Iter.second) {
Instruction *EarliestCapture = FindEarliestCapture(
Object, *const_cast<Function *>(I->getFunction()),
/*ReturnCaptures=*/false, /*StoreCaptures=*/true, DT, EphValues);
/*ReturnCaptures=*/false, /*StoreCaptures=*/true, DT);
if (EarliestCapture) {
auto Ins = Inst2Obj.insert({EarliestCapture, {}});
Ins.first->second.push_back(Object);
Expand Down
46 changes: 10 additions & 36 deletions llvm/lib/Analysis/CaptureTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
//===----------------------------------------------------------------------===//

#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,10 +73,8 @@ bool CaptureTracker::isDereferenceableOrNull(Value *O, const DataLayout &DL) {

namespace {
struct SimpleCaptureTracker : public CaptureTracker {
explicit SimpleCaptureTracker(

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

void tooManyUses() override {
LLVM_DEBUG(dbgs() << "Captured due to too many uses\n");
Expand All @@ -88,17 +85,12 @@ namespace {
if (isa<ReturnInst>(U->getUser()) && !ReturnCaptures)
return false;

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

LLVM_DEBUG(dbgs() << "Captured by: " << *U->getUser() << "\n");

Captured = true;
return true;
}

const SmallPtrSetImpl<const Value *> &EphValues;

bool ReturnCaptures;

bool Captured = false;
Expand Down Expand Up @@ -166,9 +158,8 @@ namespace {
// escape are not in a cycle.
struct EarliestCaptures : public CaptureTracker {

EarliestCaptures(bool ReturnCaptures, Function &F, const DominatorTree &DT,
const SmallPtrSetImpl<const Value *> *EphValues)
: EphValues(EphValues), DT(DT), ReturnCaptures(ReturnCaptures), F(F) {}
EarliestCaptures(bool ReturnCaptures, Function &F, const DominatorTree &DT)
: DT(DT), ReturnCaptures(ReturnCaptures), F(F) {}

void tooManyUses() override {
Captured = true;
Expand All @@ -180,9 +171,6 @@ namespace {
if (isa<ReturnInst>(I) && !ReturnCaptures)
return false;

if (EphValues && EphValues->contains(I))
return false;

if (!EarliestCapture)
EarliestCapture = I;
else
Expand All @@ -194,8 +182,6 @@ namespace {
return false;
}

const SmallPtrSetImpl<const Value *> *EphValues;

Instruction *EarliestCapture = nullptr;

const DominatorTree &DT;
Expand All @@ -217,17 +203,6 @@ namespace {
/// counts as capturing it or not.
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 @@ -239,7 +214,7 @@ bool llvm::PointerMayBeCaptured(const Value *V, bool ReturnCaptures,

LLVM_DEBUG(dbgs() << "Captured?: " << *V << " = ");

SimpleCaptureTracker SCT(EphValues, ReturnCaptures);
SimpleCaptureTracker SCT(ReturnCaptures);
PointerMayBeCaptured(V, &SCT, MaxUsesToExplore);
if (SCT.Captured)
++NumCaptured;
Expand Down Expand Up @@ -283,15 +258,14 @@ bool llvm::PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
return CB.Captured;
}

Instruction *
llvm::FindEarliestCapture(const Value *V, Function &F, bool ReturnCaptures,
bool StoreCaptures, const DominatorTree &DT,
const SmallPtrSetImpl<const Value *> *EphValues,
unsigned MaxUsesToExplore) {
Instruction *llvm::FindEarliestCapture(const Value *V, Function &F,
bool ReturnCaptures, bool StoreCaptures,
const DominatorTree &DT,
unsigned MaxUsesToExplore) {
assert(!isa<GlobalValue>(V) &&
"It doesn't make sense to ask whether a global is captured.");

EarliestCaptures CB(ReturnCaptures, F, DT, EphValues);
EarliestCaptures CB(ReturnCaptures, F, DT);
PointerMayBeCaptured(V, &CB, MaxUsesToExplore);
if (CB.Captured)
++NumCapturedBefore;
Expand Down
25 changes: 8 additions & 17 deletions llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@
#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 @@ -842,9 +840,6 @@ 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 @@ -864,10 +859,10 @@ struct DSEState {
DSEState &operator=(const DSEState &) = delete;

DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT,
PostDominatorTree &PDT, AssumptionCache &AC,
const TargetLibraryInfo &TLI, const LoopInfo &LI)
: F(F), AA(AA), EI(DT, &LI, &EphValues), BatchAA(AA, &EI), MSSA(MSSA),
DT(DT), PDT(PDT), TLI(TLI), DL(F.getParent()->getDataLayout()), LI(LI) {
PostDominatorTree &PDT, 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
// alloc-like objects.
unsigned PO = 0;
Expand Down Expand Up @@ -897,8 +892,6 @@ struct DSEState {
AnyUnreachableExit = any_of(PDT.roots(), [](const BasicBlock *E) {
return isa<UnreachableInst>(E->getTerminator());
});

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

LocationSize strengthenLocationSize(const Instruction *I,
Expand Down Expand Up @@ -1075,7 +1068,7 @@ struct DSEState {
if (!isInvisibleToCallerOnUnwind(V)) {
I.first->second = false;
} else if (isNoAliasCall(V)) {
I.first->second = !PointerMayBeCaptured(V, true, false, EphValues);
I.first->second = !PointerMayBeCaptured(V, true, false);
}
}
return I.first->second;
Expand All @@ -1094,7 +1087,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, EphValues);
I.first->second = PointerMayBeCaptured(V, false, true);
return !I.first->second;
}

Expand Down Expand Up @@ -2065,12 +2058,11 @@ 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;

DSEState State(F, AA, MSSA, DT, PDT, AC, TLI, LI);
DSEState State(F, AA, MSSA, DT, PDT, TLI, LI);
// For each store:
for (unsigned I = 0; I < State.MemDefs.size(); I++) {
MemoryDef *KillingDef = State.MemDefs[I];
Expand Down Expand Up @@ -2251,10 +2243,9 @@ 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, AC, TLI, LI);
bool Changed = eliminateDeadStores(F, AA, MSSA, DT, PDT, TLI, LI);

#ifdef LLVM_ENABLE_STATS
if (AreStatisticsEnabled())
Expand Down
3 changes: 3 additions & 0 deletions llvm/test/Transforms/DeadStoreElimination/assume.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ define void @f() {
; CHECK-NEXT: [[TMP1:%.*]] = call noalias ptr @_Znwm(i64 32)
; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt ptr [[TMP1]], @global
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP2]])
; CHECK-NEXT: store i8 0, ptr [[TMP1]], align 1
; CHECK-NEXT: ret void
;
%tmp1 = call noalias ptr @_Znwm(i64 32)
Expand All @@ -22,6 +23,7 @@ define void @f2() {
; CHECK-NEXT: [[TMP1:%.*]] = call noalias ptr @_Znwm(i64 32)
; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt ptr [[TMP1]], @global
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP2]])
; CHECK-NEXT: store i8 0, ptr [[TMP1]], align 1
; CHECK-NEXT: call void @quux(ptr @global)
; CHECK-NEXT: ret void
;
Expand All @@ -37,6 +39,7 @@ define void @f2() {
define void @pr70547() {
; CHECK-LABEL: @pr70547(
; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1
; CHECK-NEXT: store i8 0, ptr [[A]], align 1
; CHECK-NEXT: [[CALL:%.*]] = call ptr @quux(ptr [[A]]) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[CALL]], align 1
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[V]], 1
Expand Down

0 comments on commit fd95f39

Please sign in to comment.