Skip to content

Commit 3d9cf6b

Browse files
committed
[MemorySSA] Handle MemoryDef optimized away during cloning
When determining the replacement access during cloning, we currently leave accesses for instructions that are not in the VMap alone. This is correct if the instruction is not in VMap because it hasn't been cloned, but not if it has been cloned and then removed. In that case, we should walk up to the defining access, like in other simplification cases. To distinguish the two cases, pass in a callback that queries where the instruction is part of the cloned region. An alternative to this would be to delay removal of dead instructions in SimpleLoopUnswitch until after MSSA cloning.
1 parent 2eb40aa commit 3d9cf6b

File tree

4 files changed

+139
-29
lines changed

4 files changed

+139
-29
lines changed

llvm/include/llvm/Analysis/MemorySSAUpdater.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,9 @@ class MemorySSAUpdater {
276276
// representation for. No other cases are supported.
277277
void cloneUsesAndDefs(BasicBlock *BB, BasicBlock *NewBB,
278278
const ValueToValueMapTy &VMap, PhiToDefMap &MPhiMap,
279+
function_ref<bool(BasicBlock *)> IsInClonedRegion,
279280
bool CloneWasSimplified = false);
281+
280282
template <typename Iter>
281283
void privateUpdateExitBlocksForClonedLoop(ArrayRef<BasicBlock *> ExitBlocks,
282284
Iter ValuesBegin, Iter ValuesEnd,

llvm/lib/Analysis/MemorySSAUpdater.cpp

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -565,24 +565,26 @@ static MemoryAccess *onlySingleValue(MemoryPhi *MP) {
565565
return MA;
566566
}
567567

568-
static MemoryAccess *getNewDefiningAccessForClone(MemoryAccess *MA,
569-
const ValueToValueMapTy &VMap,
570-
PhiToDefMap &MPhiMap,
571-
MemorySSA *MSSA) {
568+
static MemoryAccess *getNewDefiningAccessForClone(
569+
MemoryAccess *MA, const ValueToValueMapTy &VMap, PhiToDefMap &MPhiMap,
570+
MemorySSA *MSSA, function_ref<bool(BasicBlock *BB)> IsInClonedRegion) {
572571
MemoryAccess *InsnDefining = MA;
573572
if (MemoryDef *DefMUD = dyn_cast<MemoryDef>(InsnDefining)) {
574-
if (!MSSA->isLiveOnEntryDef(DefMUD)) {
575-
Instruction *DefMUDI = DefMUD->getMemoryInst();
576-
assert(DefMUDI && "Found MemoryUseOrDef with no Instruction.");
577-
if (Instruction *NewDefMUDI =
578-
cast_or_null<Instruction>(VMap.lookup(DefMUDI))) {
579-
InsnDefining = MSSA->getMemoryAccess(NewDefMUDI);
580-
if (!InsnDefining || isa<MemoryUse>(InsnDefining)) {
581-
// The clone was simplified, it's no longer a MemoryDef, look up.
582-
InsnDefining = getNewDefiningAccessForClone(
583-
DefMUD->getDefiningAccess(), VMap, MPhiMap, MSSA);
584-
}
585-
}
573+
if (MSSA->isLiveOnEntryDef(DefMUD))
574+
return DefMUD;
575+
576+
// If the MemoryDef is not part of the cloned region, leave it alone.
577+
Instruction *DefMUDI = DefMUD->getMemoryInst();
578+
assert(DefMUDI && "Found MemoryUseOrDef with no Instruction.");
579+
if (!IsInClonedRegion(DefMUDI->getParent()))
580+
return DefMUD;
581+
582+
auto *NewDefMUDI = cast_or_null<Instruction>(VMap.lookup(DefMUDI));
583+
InsnDefining = NewDefMUDI ? MSSA->getMemoryAccess(NewDefMUDI) : nullptr;
584+
if (!InsnDefining || isa<MemoryUse>(InsnDefining)) {
585+
// The clone was simplified, it's no longer a MemoryDef, look up.
586+
InsnDefining = getNewDefiningAccessForClone(
587+
DefMUD->getDefiningAccess(), VMap, MPhiMap, MSSA, IsInClonedRegion);
586588
}
587589
} else {
588590
MemoryPhi *DefPhi = cast<MemoryPhi>(InsnDefining);
@@ -593,10 +595,10 @@ static MemoryAccess *getNewDefiningAccessForClone(MemoryAccess *MA,
593595
return InsnDefining;
594596
}
595597

596-
void MemorySSAUpdater::cloneUsesAndDefs(BasicBlock *BB, BasicBlock *NewBB,
597-
const ValueToValueMapTy &VMap,
598-
PhiToDefMap &MPhiMap,
599-
bool CloneWasSimplified) {
598+
void MemorySSAUpdater::cloneUsesAndDefs(
599+
BasicBlock *BB, BasicBlock *NewBB, const ValueToValueMapTy &VMap,
600+
PhiToDefMap &MPhiMap, function_ref<bool(BasicBlock *)> IsInClonedRegion,
601+
bool CloneWasSimplified) {
600602
const MemorySSA::AccessList *Acc = MSSA->getBlockAccesses(BB);
601603
if (!Acc)
602604
return;
@@ -615,7 +617,7 @@ void MemorySSAUpdater::cloneUsesAndDefs(BasicBlock *BB, BasicBlock *NewBB,
615617
MemoryAccess *NewUseOrDef = MSSA->createDefinedAccess(
616618
NewInsn,
617619
getNewDefiningAccessForClone(MUD->getDefiningAccess(), VMap,
618-
MPhiMap, MSSA),
620+
MPhiMap, MSSA, IsInClonedRegion),
619621
/*Template=*/CloneWasSimplified ? nullptr : MUD,
620622
/*CreationMustSucceed=*/false);
621623
if (NewUseOrDef)
@@ -668,8 +670,13 @@ void MemorySSAUpdater::updateForClonedLoop(const LoopBlocksRPO &LoopBlocks,
668670
ArrayRef<BasicBlock *> ExitBlocks,
669671
const ValueToValueMapTy &VMap,
670672
bool IgnoreIncomingWithNoClones) {
671-
PhiToDefMap MPhiMap;
673+
SmallSetVector<BasicBlock *, 16> Blocks;
674+
for (BasicBlock *BB : concat<BasicBlock *const>(LoopBlocks, ExitBlocks))
675+
Blocks.insert(BB);
672676

677+
auto IsInClonedRegion = [&](BasicBlock *BB) { return Blocks.contains(BB); };
678+
679+
PhiToDefMap MPhiMap;
673680
auto FixPhiIncomingValues = [&](MemoryPhi *Phi, MemoryPhi *NewPhi) {
674681
assert(Phi && NewPhi && "Invalid Phi nodes.");
675682
BasicBlock *NewPhiBB = NewPhi->getBlock();
@@ -692,9 +699,10 @@ void MemorySSAUpdater::updateForClonedLoop(const LoopBlocksRPO &LoopBlocks,
692699
continue;
693700

694701
// Determine incoming value and add it as incoming from IncBB.
695-
NewPhi->addIncoming(
696-
getNewDefiningAccessForClone(IncomingAccess, VMap, MPhiMap, MSSA),
697-
IncBB);
702+
NewPhi->addIncoming(getNewDefiningAccessForClone(IncomingAccess, VMap,
703+
MPhiMap, MSSA,
704+
IsInClonedRegion),
705+
IncBB);
698706
}
699707
if (auto *SingleAccess = onlySingleValue(NewPhi)) {
700708
MPhiMap[Phi] = SingleAccess;
@@ -716,13 +724,13 @@ void MemorySSAUpdater::updateForClonedLoop(const LoopBlocksRPO &LoopBlocks,
716724
MPhiMap[MPhi] = NewPhi;
717725
}
718726
// Update Uses and Defs.
719-
cloneUsesAndDefs(BB, NewBlock, VMap, MPhiMap);
727+
cloneUsesAndDefs(BB, NewBlock, VMap, MPhiMap, IsInClonedRegion);
720728
};
721729

722-
for (auto *BB : llvm::concat<BasicBlock *const>(LoopBlocks, ExitBlocks))
730+
for (auto *BB : Blocks)
723731
ProcessBlock(BB);
724732

725-
for (auto *BB : llvm::concat<BasicBlock *const>(LoopBlocks, ExitBlocks))
733+
for (auto *BB : Blocks)
726734
if (MemoryPhi *MPhi = MSSA->getMemoryAccess(BB))
727735
if (MemoryAccess *NewPhi = MPhiMap.lookup(MPhi))
728736
FixPhiIncomingValues(MPhi, cast<MemoryPhi>(NewPhi));
@@ -741,7 +749,9 @@ void MemorySSAUpdater::updateForClonedBlockIntoPred(
741749
PhiToDefMap MPhiMap;
742750
if (MemoryPhi *MPhi = MSSA->getMemoryAccess(BB))
743751
MPhiMap[MPhi] = MPhi->getIncomingValueForBlock(P1);
744-
cloneUsesAndDefs(BB, P1, VM, MPhiMap, /*CloneWasSimplified=*/true);
752+
cloneUsesAndDefs(
753+
BB, P1, VM, MPhiMap, [&](BasicBlock *CheckBB) { return BB == CheckBB; },
754+
/*CloneWasSimplified=*/true);
745755
}
746756

747757
template <typename Iter>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: opt -disable-output -passes="loop-mssa(loop-rotate),print<memoryssa>" -verify-memoryssa < %s 2>&1 | FileCheck %s
2+
3+
; CHECK: entry:
4+
; CHECK-NEXT: 3 = MemoryDef(liveOnEntry)
5+
; CHECK-NEXT: store ptr null, ptr %p, align 8
6+
; CHECK-NEXT: MemoryUse(3)
7+
; CHECK-NEXT: %val11 = load ptr, ptr %p, align 8
8+
9+
; CHECK: loop.latch:
10+
; CHECK-NEXT: 5 = MemoryPhi({loop.latch,1},{loop.latch.lr.ph,3})
11+
; CHECK-NEXT: MemoryUse(5)
12+
; CHECK-NEXT: %val2 = load ptr, ptr %p, align 8
13+
; CHECK-NEXT: 1 = MemoryDef(5)
14+
; CHECK-NEXT: store ptr null, ptr %p, align 8
15+
; CHECK-NEXT: MemoryUse(1)
16+
; CHECK-NEXT: %val1 = load ptr, ptr %p, align 8
17+
18+
; CHECK: exit:
19+
; CHECK-NEXT: 4 = MemoryPhi({entry,3},{loop.exit_crit_edge,1})
20+
21+
define void @test(ptr %p) {
22+
entry:
23+
br label %loop
24+
25+
loop:
26+
store ptr null, ptr %p
27+
%val1 = load ptr, ptr %p
28+
%cmp = icmp eq ptr %val1, null
29+
br i1 %cmp, label %exit, label %loop.latch
30+
31+
loop.latch:
32+
%val2 = load ptr, ptr %p
33+
br label %loop
34+
35+
exit:
36+
ret void
37+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
; RUN: opt -disable-output -passes="loop-mssa(simple-loop-unswitch<nontrivial>),print<memoryssa>" -verify-memoryssa < %s 2>&1 | FileCheck %s
2+
3+
declare ptr @malloc() allockind("alloc,uninitialized")
4+
5+
; CHECK-LABEL: MemorySSA for function: test
6+
7+
; CHECK: for.body.us:
8+
; CHECK-NEXT: 3 = MemoryPhi({entry.split.us,liveOnEntry},{for.body.us,3})
9+
10+
; CHECK: for.body:
11+
; CHECK-NEXT: 2 = MemoryPhi({entry.split,liveOnEntry},{for.body,1})
12+
; CHECK-NEXT: 1 = MemoryDef(2)
13+
; CHECK-NEXT: %call.i = call ptr @malloc()
14+
15+
define void @test(i1 %arg) {
16+
entry:
17+
br label %for.body
18+
19+
for.body:
20+
%call.i = call ptr @malloc()
21+
%cmp.i = icmp ne ptr %call.i, null
22+
%or.cond.i = select i1 %cmp.i, i1 %arg, i1 false
23+
br i1 %or.cond.i, label %exit, label %for.body
24+
25+
exit:
26+
ret void
27+
}
28+
29+
; CHECK-LABEL: MemorySSA for function: test_extra_defs
30+
31+
; CHECK: entry:
32+
; CHECK-NEXT: 1 = MemoryDef(liveOnEntry)
33+
; CHECK-NEXT: store i8 1, ptr %p, align 1
34+
35+
; CHECK: for.body.us:
36+
; CHECK-NEXT: 5 = MemoryPhi({entry.split.us,1},{for.body.us,6})
37+
; CHECK-NEXT: 6 = MemoryDef(5)
38+
; CHECK-NEXT: store i8 2, ptr %p, align 1
39+
40+
; CHECK: for.body:
41+
; CHECK-NEXT: 4 = MemoryPhi({entry.split,1},{for.body,3})
42+
; CHECK-NEXT: 2 = MemoryDef(4)
43+
; CHECK-NEXT: store i8 2, ptr %p
44+
; CHECK-NEXT: 3 = MemoryDef(2)
45+
; CHECK-NEXT: %call.i = call ptr @malloc()
46+
47+
define void @test_extra_defs(ptr %p, i1 %arg) {
48+
entry:
49+
store i8 1, ptr %p
50+
br label %for.body
51+
52+
for.body:
53+
store i8 2, ptr %p
54+
%call.i = call ptr @malloc()
55+
%cmp.i = icmp ne ptr %call.i, null
56+
%or.cond.i = select i1 %cmp.i, i1 %arg, i1 false
57+
br i1 %or.cond.i, label %exit, label %for.body
58+
59+
exit:
60+
ret void
61+
}

0 commit comments

Comments
 (0)