52
52
#include " llvm/IR/Argument.h"
53
53
#include " llvm/IR/BasicBlock.h"
54
54
#include " llvm/IR/Constant.h"
55
- #include " llvm/IR/ConstantRangeList.h"
56
55
#include " llvm/IR/Constants.h"
57
56
#include " llvm/IR/DataLayout.h"
58
57
#include " llvm/IR/DebugInfo.h"
@@ -165,11 +164,6 @@ static cl::opt<bool>
165
164
OptimizeMemorySSA (" dse-optimize-memoryssa" , cl::init(true ), cl::Hidden,
166
165
cl::desc(" Allow DSE to optimize memory accesses." ));
167
166
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
-
173
167
// ===----------------------------------------------------------------------===//
174
168
// Helper functions
175
169
// ===----------------------------------------------------------------------===//
@@ -815,10 +809,8 @@ bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller) {
815
809
// A memory location wrapper that represents a MemoryLocation, `MemLoc`,
816
810
// defined by `MemDef`.
817
811
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) {
822
814
assert (MemLoc.Ptr && " MemLoc should be not null" );
823
815
UnderlyingObject = getUnderlyingObject (MemLoc.Ptr );
824
816
DefInst = MemDef->getMemoryInst ();
@@ -828,59 +820,20 @@ struct MemoryLocationWrapper {
828
820
const Value *UnderlyingObject;
829
821
MemoryDef *MemDef;
830
822
Instruction *DefInst;
831
- bool DefByInitializesAttr = false ;
832
823
};
833
824
834
825
// A memory def wrapper that represents a MemoryDef and the MemoryLocation(s)
835
826
// defined by this MemoryDef.
836
827
struct MemoryDefWrapper {
837
- MemoryDefWrapper (MemoryDef *MemDef,
838
- ArrayRef<std::pair<MemoryLocation, bool >> MemLocations) {
828
+ MemoryDefWrapper (MemoryDef *MemDef, std::optional<MemoryLocation> MemLoc) {
839
829
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);
843
832
}
844
833
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;
857
835
};
858
836
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
-
884
837
struct DSEState {
885
838
Function &F;
886
839
AliasAnalysis &AA;
@@ -958,8 +911,7 @@ struct DSEState {
958
911
959
912
auto *MD = dyn_cast_or_null<MemoryDef>(MA);
960
913
if (MD && MemDefs.size () < MemorySSADefsPerBlockLimit &&
961
- (getLocForWrite (&I) || isMemTerminatorInst (&I) ||
962
- (EnableInitializesImprovement && hasInitializesAttr (&I))))
914
+ (getLocForWrite (&I) || isMemTerminatorInst (&I)))
963
915
MemDefs.push_back (MD);
964
916
}
965
917
}
@@ -1195,26 +1147,13 @@ struct DSEState {
1195
1147
return MemoryLocation::getOrNone (I);
1196
1148
}
1197
1149
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) {
1203
1151
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 ;
1215
1154
}
1216
1155
}
1217
- return Locations ;
1156
+ return getLocForWrite (I) ;
1218
1157
}
1219
1158
1220
1159
// / Assuming this instruction has a dead analyzable write, can we delete
@@ -1426,8 +1365,7 @@ struct DSEState {
1426
1365
getDomMemoryDef (MemoryDef *KillingDef, MemoryAccess *StartAccess,
1427
1366
const MemoryLocation &KillingLoc, const Value *KillingUndObj,
1428
1367
unsigned &ScanLimit, unsigned &WalkerStepLimit,
1429
- bool IsMemTerm, unsigned &PartialLimit,
1430
- bool IsInitializesAttrMemLoc) {
1368
+ bool IsMemTerm, unsigned &PartialLimit) {
1431
1369
if (ScanLimit == 0 || WalkerStepLimit == 0 ) {
1432
1370
LLVM_DEBUG (dbgs () << " \n ... hit scan limit\n " );
1433
1371
return std::nullopt;
@@ -1664,16 +1602,7 @@ struct DSEState {
1664
1602
1665
1603
// Uses which may read the original MemoryDef mean we cannot eliminate the
1666
1604
// 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)) {
1677
1606
LLVM_DEBUG (dbgs () << " ... found read clobber\n " );
1678
1607
return std::nullopt;
1679
1608
}
@@ -2242,16 +2171,6 @@ struct DSEState {
2242
2171
return MadeChange;
2243
2172
}
2244
2173
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
-
2255
2174
// Try to eliminate dead defs that access `KillingLocWrapper.MemLoc` and are
2256
2175
// killed by `KillingLocWrapper.MemDef`. Return whether
2257
2176
// any changes were made, and whether `KillingLocWrapper.DefInst` was deleted.
@@ -2263,75 +2182,6 @@ struct DSEState {
2263
2182
bool eliminateDeadDefs (const MemoryDefWrapper &KillingDefWrapper);
2264
2183
};
2265
2184
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
-
2335
2185
std::pair<bool , bool >
2336
2186
DSEState::eliminateDeadDefs (const MemoryLocationWrapper &KillingLocWrapper) {
2337
2187
bool Changed = false ;
@@ -2358,8 +2208,7 @@ DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
2358
2208
std::optional<MemoryAccess *> MaybeDeadAccess = getDomMemoryDef (
2359
2209
KillingLocWrapper.MemDef , Current, KillingLocWrapper.MemLoc ,
2360
2210
KillingLocWrapper.UnderlyingObject , ScanLimit, WalkerStepLimit,
2361
- isMemTerminatorInst (KillingLocWrapper.DefInst ), PartialLimit,
2362
- KillingLocWrapper.DefByInitializesAttr );
2211
+ isMemTerminatorInst (KillingLocWrapper.DefInst ), PartialLimit);
2363
2212
2364
2213
if (!MaybeDeadAccess) {
2365
2214
LLVM_DEBUG (dbgs () << " finished walk\n " );
@@ -2382,20 +2231,10 @@ DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
2382
2231
}
2383
2232
continue ;
2384
2233
}
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).
2392
2234
MemoryDefWrapper DeadDefWrapper (
2393
2235
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 ;
2399
2238
LLVM_DEBUG (dbgs () << " (" << *DeadLocWrapper.DefInst << " )\n " );
2400
2239
ToCheck.insert (DeadLocWrapper.MemDef ->getDefiningAccess ());
2401
2240
NumGetDomMemoryDefPassed++;
@@ -2470,41 +2309,37 @@ DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
2470
2309
}
2471
2310
2472
2311
bool DSEState::eliminateDeadDefs (const MemoryDefWrapper &KillingDefWrapper) {
2473
- if (KillingDefWrapper.DefinedLocations . empty ()) {
2312
+ if (! KillingDefWrapper.DefinedLocation . has_value ()) {
2474
2313
LLVM_DEBUG (dbgs () << " Failed to find analyzable write location for "
2475
2314
<< *KillingDefWrapper.DefInst << " \n " );
2476
2315
return false ;
2477
2316
}
2478
2317
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 ;
2506
2332
}
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;
2508
2343
}
2509
2344
2510
2345
static bool eliminateDeadStores (Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
@@ -2520,8 +2355,7 @@ static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
2520
2355
continue ;
2521
2356
2522
2357
MemoryDefWrapper KillingDefWrapper (
2523
- KillingDef, State.getLocForInst (KillingDef->getMemoryInst (),
2524
- EnableInitializesImprovement));
2358
+ KillingDef, State.getLocForInst (KillingDef->getMemoryInst ()));
2525
2359
MadeChange |= State.eliminateDeadDefs (KillingDefWrapper);
2526
2360
}
2527
2361
0 commit comments