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`.
817811struct 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.
836827struct 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-
884837struct 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-
23352185std::pair<bool , bool >
23362186DSEState::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
24722311bool 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
25102345static 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