Skip to content

Commit 13ec08c

Browse files
Revert "[DSE] Apply initializes attribute to DSE (#107282)"
This reverts commit 089237c.
1 parent 2e686d6 commit 13ec08c

File tree

2 files changed

+42
-509
lines changed

2 files changed

+42
-509
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 42 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
#include "llvm/IR/Argument.h"
5353
#include "llvm/IR/BasicBlock.h"
5454
#include "llvm/IR/Constant.h"
55-
#include "llvm/IR/ConstantRangeList.h"
5655
#include "llvm/IR/Constants.h"
5756
#include "llvm/IR/DataLayout.h"
5857
#include "llvm/IR/DebugInfo.h"
@@ -165,11 +164,6 @@ static cl::opt<bool>
165164
OptimizeMemorySSA("dse-optimize-memoryssa", cl::init(true), cl::Hidden,
166165
cl::desc("Allow DSE to optimize memory accesses."));
167166

168-
// TODO: turn on and remove this flag.
169-
static cl::opt<bool> EnableInitializesImprovement(
170-
"enable-dse-initializes-attr-improvement", cl::init(false), cl::Hidden,
171-
cl::desc("Enable the initializes attr improvement in DSE"));
172-
173167
//===----------------------------------------------------------------------===//
174168
// Helper functions
175169
//===----------------------------------------------------------------------===//
@@ -815,10 +809,8 @@ bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller) {
815809
// A memory location wrapper that represents a MemoryLocation, `MemLoc`,
816810
// defined by `MemDef`.
817811
struct MemoryLocationWrapper {
818-
MemoryLocationWrapper(MemoryLocation MemLoc, MemoryDef *MemDef,
819-
bool DefByInitializesAttr)
820-
: MemLoc(MemLoc), MemDef(MemDef),
821-
DefByInitializesAttr(DefByInitializesAttr) {
812+
MemoryLocationWrapper(MemoryLocation MemLoc, MemoryDef *MemDef)
813+
: MemLoc(MemLoc), MemDef(MemDef) {
822814
assert(MemLoc.Ptr && "MemLoc should be not null");
823815
UnderlyingObject = getUnderlyingObject(MemLoc.Ptr);
824816
DefInst = MemDef->getMemoryInst();
@@ -828,59 +820,20 @@ struct MemoryLocationWrapper {
828820
const Value *UnderlyingObject;
829821
MemoryDef *MemDef;
830822
Instruction *DefInst;
831-
bool DefByInitializesAttr = false;
832823
};
833824

834825
// A memory def wrapper that represents a MemoryDef and the MemoryLocation(s)
835826
// defined by this MemoryDef.
836827
struct MemoryDefWrapper {
837-
MemoryDefWrapper(MemoryDef *MemDef,
838-
ArrayRef<std::pair<MemoryLocation, bool>> MemLocations) {
828+
MemoryDefWrapper(MemoryDef *MemDef, std::optional<MemoryLocation> MemLoc) {
839829
DefInst = MemDef->getMemoryInst();
840-
for (auto &[MemLoc, DefByInitializesAttr] : MemLocations)
841-
DefinedLocations.push_back(
842-
MemoryLocationWrapper(MemLoc, MemDef, DefByInitializesAttr));
830+
if (MemLoc.has_value())
831+
DefinedLocation = MemoryLocationWrapper(*MemLoc, MemDef);
843832
}
844833
Instruction *DefInst;
845-
SmallVector<MemoryLocationWrapper, 1> DefinedLocations;
846-
};
847-
848-
bool hasInitializesAttr(Instruction *I) {
849-
CallBase *CB = dyn_cast<CallBase>(I);
850-
return CB && CB->getArgOperandWithAttribute(Attribute::Initializes);
851-
}
852-
853-
struct ArgumentInitInfo {
854-
unsigned Idx;
855-
bool IsDeadOrInvisibleOnUnwind;
856-
ConstantRangeList Inits;
834+
std::optional<MemoryLocationWrapper> DefinedLocation = std::nullopt;
857835
};
858836

859-
// Return the intersected range list of the initializes attributes of "Args".
860-
// "Args" are call arguments that alias to each other.
861-
// If any argument in "Args" doesn't have dead_on_unwind attr and
862-
// "CallHasNoUnwindAttr" is false, return empty.
863-
ConstantRangeList getIntersectedInitRangeList(ArrayRef<ArgumentInitInfo> Args,
864-
bool CallHasNoUnwindAttr) {
865-
if (Args.empty())
866-
return {};
867-
868-
// To address unwind, the function should have nounwind attribute or the
869-
// arguments have dead or invisible on unwind. Otherwise, return empty.
870-
for (const auto &Arg : Args) {
871-
if (!CallHasNoUnwindAttr && !Arg.IsDeadOrInvisibleOnUnwind)
872-
return {};
873-
if (Arg.Inits.empty())
874-
return {};
875-
}
876-
877-
ConstantRangeList IntersectedIntervals = Args.front().Inits;
878-
for (auto &Arg : Args.drop_front())
879-
IntersectedIntervals = IntersectedIntervals.intersectWith(Arg.Inits);
880-
881-
return IntersectedIntervals;
882-
}
883-
884837
struct DSEState {
885838
Function &F;
886839
AliasAnalysis &AA;
@@ -958,8 +911,7 @@ struct DSEState {
958911

959912
auto *MD = dyn_cast_or_null<MemoryDef>(MA);
960913
if (MD && MemDefs.size() < MemorySSADefsPerBlockLimit &&
961-
(getLocForWrite(&I) || isMemTerminatorInst(&I) ||
962-
(EnableInitializesImprovement && hasInitializesAttr(&I))))
914+
(getLocForWrite(&I) || isMemTerminatorInst(&I)))
963915
MemDefs.push_back(MD);
964916
}
965917
}
@@ -1195,26 +1147,13 @@ struct DSEState {
11951147
return MemoryLocation::getOrNone(I);
11961148
}
11971149

1198-
// Returns a list of <MemoryLocation, bool> pairs written by I.
1199-
// The bool means whether the write is from Initializes attr.
1200-
SmallVector<std::pair<MemoryLocation, bool>, 1>
1201-
getLocForInst(Instruction *I, bool ConsiderInitializesAttr) {
1202-
SmallVector<std::pair<MemoryLocation, bool>, 1> Locations;
1150+
std::optional<MemoryLocation> getLocForInst(Instruction *I) {
12031151
if (isMemTerminatorInst(I)) {
1204-
if (auto Loc = getLocForTerminator(I))
1205-
Locations.push_back(std::make_pair(Loc->first, false));
1206-
return Locations;
1207-
}
1208-
1209-
if (auto Loc = getLocForWrite(I))
1210-
Locations.push_back(std::make_pair(*Loc, false));
1211-
1212-
if (ConsiderInitializesAttr) {
1213-
for (auto &MemLoc : getInitializesArgMemLoc(I)) {
1214-
Locations.push_back(std::make_pair(MemLoc, true));
1152+
if (auto Loc = getLocForTerminator(I)) {
1153+
return Loc->first;
12151154
}
12161155
}
1217-
return Locations;
1156+
return getLocForWrite(I);
12181157
}
12191158

12201159
/// Assuming this instruction has a dead analyzable write, can we delete
@@ -1426,8 +1365,7 @@ struct DSEState {
14261365
getDomMemoryDef(MemoryDef *KillingDef, MemoryAccess *StartAccess,
14271366
const MemoryLocation &KillingLoc, const Value *KillingUndObj,
14281367
unsigned &ScanLimit, unsigned &WalkerStepLimit,
1429-
bool IsMemTerm, unsigned &PartialLimit,
1430-
bool IsInitializesAttrMemLoc) {
1368+
bool IsMemTerm, unsigned &PartialLimit) {
14311369
if (ScanLimit == 0 || WalkerStepLimit == 0) {
14321370
LLVM_DEBUG(dbgs() << "\n ... hit scan limit\n");
14331371
return std::nullopt;
@@ -1664,16 +1602,7 @@ struct DSEState {
16641602

16651603
// Uses which may read the original MemoryDef mean we cannot eliminate the
16661604
// original MD. Stop walk.
1667-
// If KillingDef is a CallInst with "initializes" attribute, the reads in
1668-
// the callee would be dominated by initializations, so it should be safe.
1669-
bool IsKillingDefFromInitAttr = false;
1670-
if (IsInitializesAttrMemLoc) {
1671-
if (KillingI == UseInst &&
1672-
KillingUndObj == getUnderlyingObject(MaybeDeadLoc.Ptr))
1673-
IsKillingDefFromInitAttr = true;
1674-
}
1675-
1676-
if (isReadClobber(MaybeDeadLoc, UseInst) && !IsKillingDefFromInitAttr) {
1605+
if (isReadClobber(MaybeDeadLoc, UseInst)) {
16771606
LLVM_DEBUG(dbgs() << " ... found read clobber\n");
16781607
return std::nullopt;
16791608
}
@@ -2242,16 +2171,6 @@ struct DSEState {
22422171
return MadeChange;
22432172
}
22442173

2245-
// Return the locations written by the initializes attribute.
2246-
// Note that this function considers:
2247-
// 1. Unwind edge: use "initializes" attribute only if the callee has
2248-
// "nounwind" attribute, or the argument has "dead_on_unwind" attribute,
2249-
// or the argument is invisible to caller on unwind. That is, we don't
2250-
// perform incorrect DSE on unwind edges in the current function.
2251-
// 2. Argument alias: for aliasing arguments, the "initializes" attribute is
2252-
// the intersected range list of their "initializes" attributes.
2253-
SmallVector<MemoryLocation, 1> getInitializesArgMemLoc(const Instruction *I);
2254-
22552174
// Try to eliminate dead defs that access `KillingLocWrapper.MemLoc` and are
22562175
// killed by `KillingLocWrapper.MemDef`. Return whether
22572176
// any changes were made, and whether `KillingLocWrapper.DefInst` was deleted.
@@ -2263,75 +2182,6 @@ struct DSEState {
22632182
bool eliminateDeadDefs(const MemoryDefWrapper &KillingDefWrapper);
22642183
};
22652184

2266-
SmallVector<MemoryLocation, 1>
2267-
DSEState::getInitializesArgMemLoc(const Instruction *I) {
2268-
const CallBase *CB = dyn_cast<CallBase>(I);
2269-
if (!CB)
2270-
return {};
2271-
2272-
// Collect aliasing arguments and their initializes ranges.
2273-
SmallMapVector<Value *, SmallVector<ArgumentInitInfo, 2>, 2> Arguments;
2274-
for (unsigned Idx = 0, Count = CB->arg_size(); Idx < Count; ++Idx) {
2275-
ConstantRangeList Inits;
2276-
Attribute InitializesAttr = CB->getParamAttr(Idx, Attribute::Initializes);
2277-
if (InitializesAttr.isValid())
2278-
Inits = InitializesAttr.getValueAsConstantRangeList();
2279-
2280-
Value *CurArg = CB->getArgOperand(Idx);
2281-
// We don't perform incorrect DSE on unwind edges in the current function,
2282-
// and use the "initializes" attribute to kill dead stores if:
2283-
// - The call does not throw exceptions, "CB->doesNotThrow()".
2284-
// - Or the callee parameter has "dead_on_unwind" attribute.
2285-
// - Or the argument is invisible to caller on unwind, and there are no
2286-
// unwind edges from this call in the current function (e.g. `CallInst`).
2287-
bool IsDeadOrInvisibleOnUnwind =
2288-
CB->paramHasAttr(Idx, Attribute::DeadOnUnwind) ||
2289-
(isa<CallInst>(CB) && isInvisibleToCallerOnUnwind(CurArg));
2290-
ArgumentInitInfo InitInfo{Idx, IsDeadOrInvisibleOnUnwind, Inits};
2291-
bool FoundAliasing = false;
2292-
for (auto &[Arg, AliasList] : Arguments) {
2293-
auto AAR = BatchAA.alias(MemoryLocation::getBeforeOrAfter(Arg),
2294-
MemoryLocation::getBeforeOrAfter(CurArg));
2295-
if (AAR == AliasResult::NoAlias) {
2296-
continue;
2297-
} else if (AAR == AliasResult::MustAlias) {
2298-
FoundAliasing = true;
2299-
AliasList.push_back(InitInfo);
2300-
} else {
2301-
// For PartialAlias and MayAlias, there is an offset or may be an
2302-
// unknown offset between the arguments and we insert an empty init
2303-
// range to discard the entire initializes info while intersecting.
2304-
FoundAliasing = true;
2305-
AliasList.push_back(ArgumentInitInfo{Idx, IsDeadOrInvisibleOnUnwind,
2306-
ConstantRangeList()});
2307-
}
2308-
}
2309-
if (!FoundAliasing)
2310-
Arguments[CurArg] = {InitInfo};
2311-
}
2312-
2313-
SmallVector<MemoryLocation, 1> Locations;
2314-
for (const auto &[_, Args] : Arguments) {
2315-
auto IntersectedRanges =
2316-
getIntersectedInitRangeList(Args, CB->doesNotThrow());
2317-
if (IntersectedRanges.empty())
2318-
continue;
2319-
2320-
for (const auto &Arg : Args) {
2321-
for (const auto &Range : IntersectedRanges) {
2322-
int64_t Start = Range.getLower().getSExtValue();
2323-
int64_t End = Range.getUpper().getSExtValue();
2324-
// For now, we only handle locations starting at offset 0.
2325-
if (Start == 0)
2326-
Locations.push_back(MemoryLocation(CB->getArgOperand(Arg.Idx),
2327-
LocationSize::precise(End - Start),
2328-
CB->getAAMetadata()));
2329-
}
2330-
}
2331-
}
2332-
return Locations;
2333-
}
2334-
23352185
std::pair<bool, bool>
23362186
DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
23372187
bool Changed = false;
@@ -2358,8 +2208,7 @@ DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
23582208
std::optional<MemoryAccess *> MaybeDeadAccess = getDomMemoryDef(
23592209
KillingLocWrapper.MemDef, Current, KillingLocWrapper.MemLoc,
23602210
KillingLocWrapper.UnderlyingObject, ScanLimit, WalkerStepLimit,
2361-
isMemTerminatorInst(KillingLocWrapper.DefInst), PartialLimit,
2362-
KillingLocWrapper.DefByInitializesAttr);
2211+
isMemTerminatorInst(KillingLocWrapper.DefInst), PartialLimit);
23632212

23642213
if (!MaybeDeadAccess) {
23652214
LLVM_DEBUG(dbgs() << " finished walk\n");
@@ -2382,20 +2231,10 @@ DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
23822231
}
23832232
continue;
23842233
}
2385-
// We cannot apply the initializes attribute to DeadAccess/DeadDef.
2386-
// It would incorrectly consider a call instruction as redundant store
2387-
// and remove this call instruction.
2388-
// TODO: this conflates the existence of a MemoryLocation with being able
2389-
// to delete the instruction. Fix isRemovable() to consider calls with
2390-
// side effects that cannot be removed, e.g. calls with the initializes
2391-
// attribute, and remove getLocForInst(ConsiderInitializesAttr = false).
23922234
MemoryDefWrapper DeadDefWrapper(
23932235
cast<MemoryDef>(DeadAccess),
2394-
getLocForInst(cast<MemoryDef>(DeadAccess)->getMemoryInst(),
2395-
/*ConsiderInitializesAttr=*/false));
2396-
assert(DeadDefWrapper.DefinedLocations.size() == 1);
2397-
MemoryLocationWrapper &DeadLocWrapper =
2398-
DeadDefWrapper.DefinedLocations.front();
2236+
getLocForInst(cast<MemoryDef>(DeadAccess)->getMemoryInst()));
2237+
MemoryLocationWrapper &DeadLocWrapper = *DeadDefWrapper.DefinedLocation;
23992238
LLVM_DEBUG(dbgs() << " (" << *DeadLocWrapper.DefInst << ")\n");
24002239
ToCheck.insert(DeadLocWrapper.MemDef->getDefiningAccess());
24012240
NumGetDomMemoryDefPassed++;
@@ -2470,41 +2309,37 @@ DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
24702309
}
24712310

24722311
bool DSEState::eliminateDeadDefs(const MemoryDefWrapper &KillingDefWrapper) {
2473-
if (KillingDefWrapper.DefinedLocations.empty()) {
2312+
if (!KillingDefWrapper.DefinedLocation.has_value()) {
24742313
LLVM_DEBUG(dbgs() << "Failed to find analyzable write location for "
24752314
<< *KillingDefWrapper.DefInst << "\n");
24762315
return false;
24772316
}
24782317

2479-
bool MadeChange = false;
2480-
for (auto &KillingLocWrapper : KillingDefWrapper.DefinedLocations) {
2481-
LLVM_DEBUG(dbgs() << "Trying to eliminate MemoryDefs killed by "
2482-
<< *KillingLocWrapper.MemDef << " ("
2483-
<< *KillingLocWrapper.DefInst << ")\n");
2484-
auto [Changed, DeletedKillingLoc] = eliminateDeadDefs(KillingLocWrapper);
2485-
2486-
// Check if the store is a no-op.
2487-
if (!DeletedKillingLoc && storeIsNoop(KillingLocWrapper.MemDef,
2488-
KillingLocWrapper.UnderlyingObject)) {
2489-
LLVM_DEBUG(dbgs() << "DSE: Remove No-Op Store:\n DEAD: "
2490-
<< *KillingLocWrapper.DefInst << '\n');
2491-
deleteDeadInstruction(KillingLocWrapper.DefInst);
2492-
NumRedundantStores++;
2493-
MadeChange = true;
2494-
continue;
2495-
}
2496-
// Can we form a calloc from a memset/malloc pair?
2497-
if (!DeletedKillingLoc &&
2498-
tryFoldIntoCalloc(KillingLocWrapper.MemDef,
2499-
KillingLocWrapper.UnderlyingObject)) {
2500-
LLVM_DEBUG(dbgs() << "DSE: Remove memset after forming calloc:\n"
2501-
<< " DEAD: " << *KillingLocWrapper.DefInst << '\n');
2502-
deleteDeadInstruction(KillingLocWrapper.DefInst);
2503-
MadeChange = true;
2504-
continue;
2505-
}
2318+
auto &KillingLocWrapper = *KillingDefWrapper.DefinedLocation;
2319+
LLVM_DEBUG(dbgs() << "Trying to eliminate MemoryDefs killed by "
2320+
<< *KillingLocWrapper.MemDef << " ("
2321+
<< *KillingLocWrapper.DefInst << ")\n");
2322+
auto [Changed, DeletedKillingLoc] = eliminateDeadDefs(KillingLocWrapper);
2323+
2324+
// Check if the store is a no-op.
2325+
if (!DeletedKillingLoc && storeIsNoop(KillingLocWrapper.MemDef,
2326+
KillingLocWrapper.UnderlyingObject)) {
2327+
LLVM_DEBUG(dbgs() << "DSE: Remove No-Op Store:\n DEAD: "
2328+
<< *KillingLocWrapper.DefInst << '\n');
2329+
deleteDeadInstruction(KillingLocWrapper.DefInst);
2330+
NumRedundantStores++;
2331+
return true;
25062332
}
2507-
return MadeChange;
2333+
// Can we form a calloc from a memset/malloc pair?
2334+
if (!DeletedKillingLoc &&
2335+
tryFoldIntoCalloc(KillingLocWrapper.MemDef,
2336+
KillingLocWrapper.UnderlyingObject)) {
2337+
LLVM_DEBUG(dbgs() << "DSE: Remove memset after forming calloc:\n"
2338+
<< " DEAD: " << *KillingLocWrapper.DefInst << '\n');
2339+
deleteDeadInstruction(KillingLocWrapper.DefInst);
2340+
return true;
2341+
}
2342+
return Changed;
25082343
}
25092344

25102345
static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
@@ -2520,8 +2355,7 @@ static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
25202355
continue;
25212356

25222357
MemoryDefWrapper KillingDefWrapper(
2523-
KillingDef, State.getLocForInst(KillingDef->getMemoryInst(),
2524-
EnableInitializesImprovement));
2358+
KillingDef, State.getLocForInst(KillingDef->getMemoryInst()));
25252359
MadeChange |= State.eliminateDeadDefs(KillingDefWrapper);
25262360
}
25272361

0 commit comments

Comments
 (0)