Skip to content

Commit

Permalink
[GuardWidening] Preserve MemorySSA
Browse files Browse the repository at this point in the history
As reported on https://bugs.llvm.org/show_bug.cgi?id=51020, the
guard widening pass doesn't preserve MemorySSA, so it can no
longer be scheduled in the same loop pass manager as LICM. However,
the loop-schedule.ll test indicates that this is supposed to work.

Fix this by preserving MemorySSA if available, as this seems to be
trivial in this case (we only need to drop the memory access for
the removed guards).

Differential Revision: https://reviews.llvm.org/D108386
  • Loading branch information
nikic committed Aug 19, 2021
1 parent 95ddc83 commit 8cf5b69
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 20 deletions.
57 changes: 43 additions & 14 deletions llvm/lib/Transforms/Scalar/GuardWidening.cpp
Expand Up @@ -46,6 +46,7 @@
#include "llvm/Analysis/GuardUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/ConstantRange.h"
Expand Down Expand Up @@ -105,15 +106,18 @@ static void setCondition(Instruction *I, Value *NewCond) {
}

// Eliminates the guard instruction properly.
static void eliminateGuard(Instruction *GuardInst) {
static void eliminateGuard(Instruction *GuardInst, MemorySSAUpdater *MSSAU) {
GuardInst->eraseFromParent();
if (MSSAU)
MSSAU->removeMemoryAccess(GuardInst);
++GuardsEliminated;
}

class GuardWideningImpl {
DominatorTree &DT;
PostDominatorTree *PDT;
LoopInfo &LI;
MemorySSAUpdater *MSSAU;

/// Together, these describe the region of interest. This might be all of
/// the blocks within a function, or only a given loop's blocks and preheader.
Expand Down Expand Up @@ -269,12 +273,12 @@ class GuardWideningImpl {
}

public:

explicit GuardWideningImpl(DominatorTree &DT, PostDominatorTree *PDT,
LoopInfo &LI, DomTreeNode *Root,
LoopInfo &LI, MemorySSAUpdater *MSSAU,
DomTreeNode *Root,
std::function<bool(BasicBlock*)> BlockFilter)
: DT(DT), PDT(PDT), LI(LI), Root(Root), BlockFilter(BlockFilter)
{}
: DT(DT), PDT(PDT), LI(LI), MSSAU(MSSAU), Root(Root),
BlockFilter(BlockFilter) {}

/// The entry point for this pass.
bool run();
Expand Down Expand Up @@ -313,7 +317,7 @@ bool GuardWideningImpl::run() {
if (!WidenedGuards.count(I)) {
assert(isa<ConstantInt>(getCondition(I)) && "Should be!");
if (isSupportedGuardInstruction(I))
eliminateGuard(I);
eliminateGuard(I, MSSAU);
else {
assert(isa<BranchInst>(I) &&
"Eliminated something other than guard or branch?");
Expand Down Expand Up @@ -766,12 +770,18 @@ PreservedAnalyses GuardWideningPass::run(Function &F,
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &LI = AM.getResult<LoopAnalysis>(F);
auto &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
if (!GuardWideningImpl(DT, &PDT, LI, DT.getRootNode(),
[](BasicBlock*) { return true; } ).run())
auto *MSSAA = AM.getCachedResult<MemorySSAAnalysis>(F);
std::unique_ptr<MemorySSAUpdater> MSSAU;
if (MSSAA)
MSSAU = std::make_unique<MemorySSAUpdater>(&MSSAA->getMSSA());
if (!GuardWideningImpl(DT, &PDT, LI, MSSAU ? MSSAU.get() : nullptr,
DT.getRootNode(), [](BasicBlock *) { return true; })
.run())
return PreservedAnalyses::all();

PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
PA.preserve<MemorySSAAnalysis>();
return PA;
}

Expand All @@ -784,11 +794,17 @@ PreservedAnalyses GuardWideningPass::run(Loop &L, LoopAnalysisManager &AM,
auto BlockFilter = [&](BasicBlock *BB) {
return BB == RootBB || L.contains(BB);
};
if (!GuardWideningImpl(AR.DT, nullptr, AR.LI, AR.DT.getNode(RootBB),
BlockFilter).run())
std::unique_ptr<MemorySSAUpdater> MSSAU;
if (AR.MSSA)
MSSAU = std::make_unique<MemorySSAUpdater>(AR.MSSA);
if (!GuardWideningImpl(AR.DT, nullptr, AR.LI, MSSAU ? MSSAU.get() : nullptr,
AR.DT.getNode(RootBB), BlockFilter).run())
return PreservedAnalyses::all();

return getLoopPassPreservedAnalyses();
auto PA = getLoopPassPreservedAnalyses();
if (AR.MSSA)
PA.preserve<MemorySSAAnalysis>();
return PA;
}

namespace {
Expand All @@ -805,15 +821,22 @@ struct GuardWideningLegacyPass : public FunctionPass {
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto &PDT = getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
return GuardWideningImpl(DT, &PDT, LI, DT.getRootNode(),
[](BasicBlock*) { return true; } ).run();
auto *MSSAWP = getAnalysisIfAvailable<MemorySSAWrapperPass>();
std::unique_ptr<MemorySSAUpdater> MSSAU;
if (MSSAWP)
MSSAU = std::make_unique<MemorySSAUpdater>(&MSSAWP->getMSSA());
return GuardWideningImpl(DT, &PDT, LI, MSSAU ? MSSAU.get() : nullptr,
DT.getRootNode(),
[](BasicBlock *) { return true; })
.run();
}

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<PostDominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
AU.addPreserved<MemorySSAWrapperPass>();
}
};

Expand All @@ -833,20 +856,26 @@ struct LoopGuardWideningLegacyPass : public LoopPass {
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto *PDTWP = getAnalysisIfAvailable<PostDominatorTreeWrapperPass>();
auto *PDT = PDTWP ? &PDTWP->getPostDomTree() : nullptr;
auto *MSSAWP = getAnalysisIfAvailable<MemorySSAWrapperPass>();
std::unique_ptr<MemorySSAUpdater> MSSAU;
if (MSSAWP)
MSSAU = std::make_unique<MemorySSAUpdater>(&MSSAWP->getMSSA());

BasicBlock *RootBB = L->getLoopPredecessor();
if (!RootBB)
RootBB = L->getHeader();
auto BlockFilter = [&](BasicBlock *BB) {
return BB == RootBB || L->contains(BB);
};
return GuardWideningImpl(DT, PDT, LI,
return GuardWideningImpl(DT, PDT, LI, MSSAU ? MSSAU.get() : nullptr,
DT.getNode(RootBB), BlockFilter).run();
}

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
getLoopAnalysisUsage(AU);
AU.addPreserved<PostDominatorTreeWrapperPass>();
AU.addPreserved<MemorySSAWrapperPass>();
}
};
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/GuardWidening/basic-loop.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -loop-guard-widening -enable-new-pm=0 < %s | FileCheck %s
; RUN: opt -S -passes="loop(guard-widening)" < %s | FileCheck %s
; RUN: opt -S -loop-guard-widening -verify-memoryssa -enable-new-pm=0 < %s | FileCheck %s
; RUN: opt -S -passes="loop-mssa(guard-widening)" -verify-memoryssa < %s | FileCheck %s

declare void @llvm.experimental.guard(i1,...)

Expand Down
8 changes: 4 additions & 4 deletions llvm/test/Transforms/GuardWidening/loop-schedule.ll
@@ -1,13 +1,13 @@
; RUN: opt -S -licm -loop-guard-widening -licm -debug-pass=Structure -enable-new-pm=0 < %s 2>&1 | FileCheck %s --check-prefixes=LPM,CHECK
; RUN: opt -S -passes='licm,guard-widening,licm' -debug-pass-manager < %s 2>&1 | FileCheck %s --check-prefixes=NPM,CHECK
; RUN: opt -S -licm -loop-guard-widening -licm -verify-memoryssa -debug-pass=Structure -enable-new-pm=0 < %s 2>&1 | FileCheck %s --check-prefixes=LPM,CHECK
; RUN: opt -S -passes='licm,guard-widening,licm' -verify-memoryssa -debug-pass-manager < %s 2>&1 | FileCheck %s --check-prefixes=NPM,CHECK

; Main point of this test is to check the scheduling -- there should be
; no analysis passes needed between LICM and LoopGuardWidening

; LPM: Loop Pass Manager
; LPM: Loop Invariant Code Motion
; LPM: Widen guards (within a single loop, as a loop pass)
; LPM: Loop Invariant Code Motion
; LPM-NEXT: Widen guards (within a single loop, as a loop pass)
; LPM-NEXT: Loop Invariant Code Motion

; NPM: LICMPass
; NPM-NEXT: GuardWideningPass
Expand Down

0 comments on commit 8cf5b69

Please sign in to comment.