Skip to content

Commit 3d8f842

Browse files
committed
[LICM] Make promotion faster
Even when MemorySSA-based LICM is used, an AST is still populated for scalar promotion. As the AST has quadratic complexity, a lot of time is spent in this step despite the existing access count limit. This patch optimizes the identification of promotable stores. The idea here is pretty simple: We're only interested in must-alias mod sets of loop invariant pointers. As such, only populate the AST with loop-invariant loads and stores (anything else is definitely not promotable) and then discard any sets which alias with any of the remaining, definitely non-promotable accesses. If we promoted something, check whether this has made some other accesses loop invariant and thus possible promotion candidates. This is much faster in practice, because we need to perform AA queries for O(NumPromotable^2 + NumPromotable*NumNonPromotable) instead of O(NumTotal^2), and NumPromotable tends to be small. Additionally, promotable accesses have loop invariant pointers, for which AA is cheaper. This has a signicant positive compile-time impact. We save ~1.8% geomean on CTMark at O3, with 6% on lencod in particular and 25% on individual files. Conceptually, this change is NFC, but may not be so in practice, because the AST is only an approximation, and can produce different results depending on the order in which accesses are added. However, there is at least no impact on the number of promotions (licm.NumPromoted) in test-suite O3 configuration with this change. Differential Revision: https://reviews.llvm.org/D89264
1 parent 51cdb78 commit 3d8f842

File tree

3 files changed

+120
-52
lines changed

3 files changed

+120
-52
lines changed

llvm/include/llvm/Analysis/AliasSetTracker.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/ADT/DenseMapInfo.h"
2121
#include "llvm/ADT/ilist.h"
2222
#include "llvm/ADT/ilist_node.h"
23+
#include "llvm/Analysis/AliasAnalysis.h"
2324
#include "llvm/Analysis/MemoryLocation.h"
2425
#include "llvm/IR/Instruction.h"
2526
#include "llvm/IR/Metadata.h"
@@ -39,7 +40,6 @@ class AliasSetTracker;
3940
class BasicBlock;
4041
class LoadInst;
4142
class Loop;
42-
class MemorySSA;
4343
class AnyMemSetInst;
4444
class AnyMemTransferInst;
4545
class raw_ostream;
@@ -343,7 +343,6 @@ class AliasSetTracker {
343343
struct ASTCallbackVHDenseMapInfo : public DenseMapInfo<Value *> {};
344344

345345
AAResults &AA;
346-
MemorySSA *MSSA = nullptr;
347346
Loop *L = nullptr;
348347
ilist<AliasSet> AliasSets;
349348

@@ -357,8 +356,6 @@ class AliasSetTracker {
357356
/// Create an empty collection of AliasSets, and use the specified alias
358357
/// analysis object to disambiguate load and store addresses.
359358
explicit AliasSetTracker(AAResults &AA) : AA(AA) {}
360-
explicit AliasSetTracker(AAResults &AA, MemorySSA *MSSA, Loop *L)
361-
: AA(AA), MSSA(MSSA), L(L) {}
362359
~AliasSetTracker() { clear(); }
363360

364361
/// These methods are used to add different types of instructions to the alias
@@ -383,7 +380,6 @@ class AliasSetTracker {
383380
void add(BasicBlock &BB); // Add all instructions in basic block
384381
void add(const AliasSetTracker &AST); // Add alias relations from another AST
385382
void addUnknown(Instruction *I);
386-
void addAllInstructionsInLoopUsingMSSA();
387383

388384
void clear();
389385

llvm/lib/Analysis/AliasSetTracker.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "llvm/Analysis/GuardUtils.h"
1515
#include "llvm/Analysis/LoopInfo.h"
1616
#include "llvm/Analysis/MemoryLocation.h"
17-
#include "llvm/Analysis/MemorySSA.h"
1817
#include "llvm/Config/llvm-config.h"
1918
#include "llvm/IR/Constants.h"
2019
#include "llvm/IR/DataLayout.h"
@@ -536,15 +535,6 @@ void AliasSetTracker::add(const AliasSetTracker &AST) {
536535
}
537536
}
538537

539-
void AliasSetTracker::addAllInstructionsInLoopUsingMSSA() {
540-
assert(MSSA && L && "MSSA and L must be available");
541-
for (const BasicBlock *BB : L->blocks())
542-
if (auto *Accesses = MSSA->getBlockAccesses(BB))
543-
for (auto &Access : *Accesses)
544-
if (auto *MUD = dyn_cast<MemoryUseOrDef>(&Access))
545-
add(MUD->getMemoryInst());
546-
}
547-
548538
// deleteValue method - This method is used to remove a pointer value from the
549539
// AliasSetTracker entirely. It should be used when an instruction is deleted
550540
// from the program to update the AST. If you don't use this, you would have

llvm/lib/Transforms/Scalar/LICM.cpp

Lines changed: 119 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ static void moveInstructionBefore(Instruction &I, Instruction &Dest,
185185
ICFLoopSafetyInfo &SafetyInfo,
186186
MemorySSAUpdater *MSSAU, ScalarEvolution *SE);
187187

188+
static void foreachMemoryAccess(MemorySSA *MSSA, Loop *L,
189+
function_ref<void(Instruction *)> Fn);
190+
static SmallVector<SmallSetVector<Value *, 8>, 0>
191+
collectPromotionCandidates(MemorySSA *MSSA, AliasAnalysis *AA, Loop *L,
192+
SmallVectorImpl<Instruction *> &MaybePromotable);
193+
188194
namespace {
189195
struct LoopInvariantCodeMotion {
190196
bool runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI, DominatorTree *DT,
@@ -203,9 +209,6 @@ struct LoopInvariantCodeMotion {
203209

204210
std::unique_ptr<AliasSetTracker>
205211
collectAliasInfoForLoop(Loop *L, LoopInfo *LI, AAResults *AA);
206-
std::unique_ptr<AliasSetTracker>
207-
collectAliasInfoForLoopWithMSSA(Loop *L, AAResults *AA,
208-
MemorySSAUpdater *MSSAU);
209212
};
210213

211214
struct LegacyLICMPass : public LoopPass {
@@ -430,31 +433,48 @@ bool LoopInvariantCodeMotion::runOnLoop(
430433
PredIteratorCache PIC;
431434

432435
bool Promoted = false;
433-
434-
// Build an AST using MSSA.
435-
if (!CurAST.get())
436-
CurAST = collectAliasInfoForLoopWithMSSA(L, AA, MSSAU.get());
437-
438-
// Loop over all of the alias sets in the tracker object.
439-
for (AliasSet &AS : *CurAST) {
440-
// We can promote this alias set if it has a store, if it is a "Must"
441-
// alias set, if the pointer is loop invariant, and if we are not
442-
// eliminating any volatile loads or stores.
443-
if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() ||
444-
!L->isLoopInvariant(AS.begin()->getValue()))
445-
continue;
446-
447-
assert(
448-
!AS.empty() &&
449-
"Must alias set should have at least one pointer element in it!");
450-
451-
SmallSetVector<Value *, 8> PointerMustAliases;
452-
for (const auto &ASI : AS)
453-
PointerMustAliases.insert(ASI.getValue());
454-
455-
Promoted |= promoteLoopAccessesToScalars(
456-
PointerMustAliases, ExitBlocks, InsertPts, MSSAInsertPts, PIC, LI,
457-
DT, TLI, L, CurAST.get(), MSSAU.get(), &SafetyInfo, ORE);
436+
if (CurAST.get()) {
437+
// Loop over all of the alias sets in the tracker object.
438+
for (AliasSet &AS : *CurAST) {
439+
// We can promote this alias set if it has a store, if it is a "Must"
440+
// alias set, if the pointer is loop invariant, and if we are not
441+
// eliminating any volatile loads or stores.
442+
if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() ||
443+
!L->isLoopInvariant(AS.begin()->getValue()))
444+
continue;
445+
446+
assert(
447+
!AS.empty() &&
448+
"Must alias set should have at least one pointer element in it!");
449+
450+
SmallSetVector<Value *, 8> PointerMustAliases;
451+
for (const auto &ASI : AS)
452+
PointerMustAliases.insert(ASI.getValue());
453+
454+
Promoted |= promoteLoopAccessesToScalars(
455+
PointerMustAliases, ExitBlocks, InsertPts, MSSAInsertPts, PIC, LI,
456+
DT, TLI, L, CurAST.get(), MSSAU.get(), &SafetyInfo, ORE);
457+
}
458+
} else {
459+
SmallVector<Instruction *, 16> MaybePromotable;
460+
foreachMemoryAccess(MSSA, L, [&](Instruction *I) {
461+
MaybePromotable.push_back(I);
462+
});
463+
464+
// Promoting one set of accesses may make the pointers for another set
465+
// loop invariant, so run this in a loop (with the MaybePromotable set
466+
// decreasing in size over time).
467+
bool LocalPromoted;
468+
do {
469+
LocalPromoted = false;
470+
for (const SmallSetVector<Value *, 8> &PointerMustAliases :
471+
collectPromotionCandidates(MSSA, AA, L, MaybePromotable)) {
472+
LocalPromoted |= promoteLoopAccessesToScalars(
473+
PointerMustAliases, ExitBlocks, InsertPts, MSSAInsertPts, PIC,
474+
LI, DT, TLI, L, /*AST*/nullptr, MSSAU.get(), &SafetyInfo, ORE);
475+
}
476+
Promoted |= LocalPromoted;
477+
} while (LocalPromoted);
458478
}
459479

460480
// Once we have promoted values across the loop body we have to
@@ -2217,6 +2237,77 @@ bool llvm::promoteLoopAccessesToScalars(
22172237
return true;
22182238
}
22192239

2240+
static void foreachMemoryAccess(MemorySSA *MSSA, Loop *L,
2241+
function_ref<void(Instruction *)> Fn) {
2242+
for (const BasicBlock *BB : L->blocks())
2243+
if (const auto *Accesses = MSSA->getBlockAccesses(BB))
2244+
for (const auto &Access : *Accesses)
2245+
if (const auto *MUD = dyn_cast<MemoryUseOrDef>(&Access))
2246+
Fn(MUD->getMemoryInst());
2247+
}
2248+
2249+
static SmallVector<SmallSetVector<Value *, 8>, 0>
2250+
collectPromotionCandidates(MemorySSA *MSSA, AliasAnalysis *AA, Loop *L,
2251+
SmallVectorImpl<Instruction *> &MaybePromotable) {
2252+
AliasSetTracker AST(*AA);
2253+
2254+
auto IsPotentiallyPromotable = [L](const Instruction *I) {
2255+
if (const auto *SI = dyn_cast<StoreInst>(I))
2256+
return L->isLoopInvariant(SI->getPointerOperand());
2257+
if (const auto *LI = dyn_cast<LoadInst>(I))
2258+
return L->isLoopInvariant(LI->getPointerOperand());
2259+
return false;
2260+
};
2261+
2262+
// Populate AST with potentially promotable accesses and remove them from
2263+
// MaybePromotable, so they will not be checked again on the next iteration.
2264+
SmallPtrSet<Value *, 16> AttemptingPromotion;
2265+
llvm::erase_if(MaybePromotable, [&](Instruction *I) {
2266+
if (IsPotentiallyPromotable(I)) {
2267+
AttemptingPromotion.insert(I);
2268+
AST.add(I);
2269+
return true;
2270+
}
2271+
return false;
2272+
});
2273+
2274+
// We're only interested in must-alias sets that contain a mod.
2275+
SmallVector<const AliasSet *, 8> Sets;
2276+
for (AliasSet &AS : AST)
2277+
if (!AS.isForwardingAliasSet() && AS.isMod() && AS.isMustAlias())
2278+
Sets.push_back(&AS);
2279+
2280+
if (Sets.empty())
2281+
return {}; // Nothing to promote...
2282+
2283+
// Discard any sets for which there is an aliasing non-promotable access.
2284+
foreachMemoryAccess(MSSA, L, [&](Instruction *I) {
2285+
if (AttemptingPromotion.contains(I))
2286+
return;
2287+
2288+
if (Optional<MemoryLocation> Loc = MemoryLocation::getOrNone(I)) {
2289+
llvm::erase_if(Sets, [&](const AliasSet *AS) {
2290+
return AS->aliasesPointer(Loc->Ptr, Loc->Size, Loc->AATags, *AA)
2291+
!= NoAlias;
2292+
});
2293+
} else {
2294+
llvm::erase_if(Sets, [&](const AliasSet *AS) {
2295+
return AS->aliasesUnknownInst(I, *AA);
2296+
});
2297+
}
2298+
});
2299+
2300+
SmallVector<SmallSetVector<Value *, 8>, 0> Result;
2301+
for (const AliasSet *Set : Sets) {
2302+
SmallSetVector<Value *, 8> PointerMustAliases;
2303+
for (const auto &ASI : *Set)
2304+
PointerMustAliases.insert(ASI.getValue());
2305+
Result.push_back(std::move(PointerMustAliases));
2306+
}
2307+
2308+
return Result;
2309+
}
2310+
22202311
/// Returns an owning pointer to an alias set which incorporates aliasing info
22212312
/// from L and all subloops of L.
22222313
std::unique_ptr<AliasSetTracker>
@@ -2237,15 +2328,6 @@ LoopInvariantCodeMotion::collectAliasInfoForLoop(Loop *L, LoopInfo *LI,
22372328
return CurAST;
22382329
}
22392330

2240-
std::unique_ptr<AliasSetTracker>
2241-
LoopInvariantCodeMotion::collectAliasInfoForLoopWithMSSA(
2242-
Loop *L, AAResults *AA, MemorySSAUpdater *MSSAU) {
2243-
auto *MSSA = MSSAU->getMemorySSA();
2244-
auto CurAST = std::make_unique<AliasSetTracker>(*AA, MSSA, L);
2245-
CurAST->addAllInstructionsInLoopUsingMSSA();
2246-
return CurAST;
2247-
}
2248-
22492331
static bool pointerInvalidatedByLoop(MemoryLocation MemLoc,
22502332
AliasSetTracker *CurAST, Loop *CurLoop,
22512333
AAResults *AA) {

0 commit comments

Comments
 (0)