Skip to content

Commit

Permalink
GVN-hoist: compute MSSA once per function (PR28670)
Browse files Browse the repository at this point in the history
With this patch we compute the MemorySSA once and update it in the code generator.

Differential Revision: https://reviews.llvm.org/D22966

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@277649 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
sebpop committed Aug 3, 2016
1 parent 5494503 commit a9161e1
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 12 deletions.
61 changes: 49 additions & 12 deletions lib/Transforms/Scalar/GVNHoist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,30 +193,27 @@ class GVNHoist {
VN.setAliasAnalysis(AA);
VN.setMemDep(MD);
bool Res = false;
MemorySSA M(F, AA, DT);
MSSA = &M;

// FIXME: use lazy evaluation of VN to avoid the fix-point computation.
while (1) {
// FIXME: only compute MemorySSA once. We need to update the analysis in
// the same time as transforming the code.
MemorySSA M(F, AA, DT);
MSSA = &M;

// Perform DFS Numbering of instructions.
unsigned I = 0;
for (const BasicBlock *BB : depth_first(&F.getEntryBlock()))
for (auto &Inst: *BB)
DFSNumber.insert({&Inst, ++I});

auto HoistStat = hoistExpressions(F);
if (HoistStat.first + HoistStat.second == 0) {
if (HoistStat.first + HoistStat.second == 0)
return Res;
}
if (HoistStat.second > 0) {

if (HoistStat.second > 0)
// To address a limitation of the current GVN, we need to rerun the
// hoisting after we hoisted loads in order to be able to hoist all
// scalars dependent on the hoisted loads. Same for stores.
// hoisting after we hoisted loads or stores in order to be able to
// hoist all scalars dependent on the hoisted ld/st.
VN.clear();
}

Res = true;

// DFS numbers change when instructions are hoisted: clear and recompute.
Expand Down Expand Up @@ -310,7 +307,8 @@ class GVNHoist {

for (User *U : Def->users())
if (auto *MU = dyn_cast<MemoryUse>(U)) {
BasicBlock *UBB = MU->getBlock();
// FIXME: MU->getBlock() does not get updated when we move the instruction.
BasicBlock *UBB = MU->getMemoryInst()->getParent();
// Only analyze uses in BB.
if (BB != UBB)
continue;
Expand Down Expand Up @@ -742,9 +740,23 @@ class GVNHoist {
!makeGepOperandsAvailable(Repl, HoistPt, InstructionsToHoist))
continue;

// Move the instruction at the end of HoistPt.
Repl->moveBefore(HoistPt->getTerminator());
}

MemoryAccess *NewMemAcc = nullptr;
if (MemoryAccess *MA = MSSA->getMemoryAccess(Repl)) {
if (MemoryUseOrDef *OldMemAcc = dyn_cast<MemoryUseOrDef>(MA)) {
// The definition of this ld/st will not change: ld/st hoisting is
// legal when the ld/st is not moved past its current definition.
MemoryAccess *Def = OldMemAcc->getDefiningAccess();
NewMemAcc = MSSA->createMemoryAccessInBB(Repl, Def, HoistPt,
MemorySSA::End);
OldMemAcc->replaceAllUsesWith(NewMemAcc);
MSSA->removeMemoryAccess(OldMemAcc);
}
}

if (isa<LoadInst>(Repl))
++NL;
else if (isa<StoreInst>(Repl))
Expand Down Expand Up @@ -775,11 +787,36 @@ class GVNHoist {
} else if (isa<CallInst>(Repl)) {
++NumCallsRemoved;
}

if (NewMemAcc) {
// Update the uses of the old MSSA access with NewMemAcc.
MemoryAccess *OldMA = MSSA->getMemoryAccess(I);
OldMA->replaceAllUsesWith(NewMemAcc);
MSSA->removeMemoryAccess(OldMA);
}

Repl->intersectOptionalDataWith(I);
combineKnownMetadata(Repl, I);
I->replaceAllUsesWith(Repl);
I->eraseFromParent();
}

// Remove MemorySSA phi nodes with the same arguments.
if (NewMemAcc) {
SmallPtrSet<MemoryPhi *, 4> UsePhis;
for (User *U : NewMemAcc->users())
if (MemoryPhi *Phi = dyn_cast<MemoryPhi>(U))
UsePhis.insert(Phi);

for (auto *Phi : UsePhis) {
auto In = Phi->incoming_values();
if (std::all_of(In.begin(), In.end(),
[&](Use &U){return U == NewMemAcc;})) {
Phi->replaceAllUsesWith(NewMemAcc);
MSSA->removeMemoryAccess(Phi);
}
}
}
}

NumHoisted += NL + NS + NC + NI;
Expand Down
69 changes: 69 additions & 0 deletions test/Transforms/GVN/hoist-mssa.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
; RUN: opt -S -gvn-hoist < %s | FileCheck %s

; Check that store hoisting works: there should be only one store left.
; CHECK-LABEL: @getopt
; CHECK: store i32
; CHECK-NOT: store i32

@optind = external global i32, align 4

define void @getopt() {
bb:
br label %bb1

bb1: ; preds = %bb
br i1 undef, label %bb2, label %bb3

bb2: ; preds = %bb1
br label %bb13

bb3: ; preds = %bb1
br i1 undef, label %bb4, label %bb9

bb4: ; preds = %bb3
%tmp = load i32, i32* @optind, align 4
br i1 undef, label %bb5, label %bb7

bb5: ; preds = %bb4
%tmp6 = add nsw i32 %tmp, 1
store i32 %tmp6, i32* @optind, align 4
br label %bb12

bb7: ; preds = %bb4
%tmp8 = add nsw i32 %tmp, 1
store i32 %tmp8, i32* @optind, align 4
br label %bb13

bb9: ; preds = %bb3
%tmp10 = load i32, i32* @optind, align 4
%tmp11 = add nsw i32 %tmp10, 1
store i32 %tmp11, i32* @optind, align 4
br label %bb12

bb12: ; preds = %bb9, %bb5
br label %bb13

bb13: ; preds = %bb12, %bb7, %bb2
ret void
}

@GlobalVar = internal global float 1.000000e+00

; Check that we hoist stores and remove the MSSA phi node.
; CHECK-LABEL: @hoistStoresUpdateMSSA
; CHECK: store float
; CHECK-NOT: store float
define float @hoistStoresUpdateMSSA(float %d) {
entry:
store float 0.000000e+00, float* @GlobalVar
%cmp = fcmp oge float %d, 0.000000e+00
br i1 %cmp, label %if.then, label %if.end

if.then:
store float 0.000000e+00, float* @GlobalVar
br label %if.end

if.end:
%tmp = load float, float* @GlobalVar, align 4
ret float %tmp
}

0 comments on commit a9161e1

Please sign in to comment.