[llvm] r297428 - NewGVN: Rewrite DCE during elimination so we do it as well as old GVN did.
Daniel Berlin via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 9 16:32:34 PST 2017
Author: dannyb
Date: Thu Mar 9 18:32:33 2017
New Revision: 297428
URL: http://llvm.org/viewvc/llvm-project?rev=297428&view=rev
Log:
NewGVN: Rewrite DCE during elimination so we do it as well as old GVN did.
Modified:
llvm/trunk/include/llvm/Transforms/Utils/Local.h
llvm/trunk/lib/Transforms/Scalar/NewGVN.cpp
llvm/trunk/lib/Transforms/Utils/Local.cpp
llvm/trunk/test/Transforms/NewGVN/load-constant-mem.ll
llvm/trunk/test/Transforms/NewGVN/pr31613.ll
llvm/trunk/test/Transforms/NewGVN/pr31682.ll
llvm/trunk/test/Transforms/NewGVN/pr31758.ll
llvm/trunk/test/Transforms/NewGVN/tbaa.ll
Modified: llvm/trunk/include/llvm/Transforms/Utils/Local.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/Local.h?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/Local.h (original)
+++ llvm/trunk/include/llvm/Transforms/Utils/Local.h Thu Mar 9 18:32:33 2017
@@ -74,6 +74,12 @@ bool ConstantFoldTerminator(BasicBlock *
bool isInstructionTriviallyDead(Instruction *I,
const TargetLibraryInfo *TLI = nullptr);
+/// Return true if the result produced by the instruction would have no side
+/// effects if it was not used. This is equivalent to checking whether
+/// isInstructionTriviallyDead would be true if the use count was 0.
+bool wouldInstructionBeTriviallyDead(Instruction *I,
+ const TargetLibraryInfo *TLI = nullptr);
+
/// If the specified value is a trivially dead instruction, delete it.
/// If that makes any of its operands trivially dead, delete them too,
/// recursively. Return true if any instructions were deleted.
Modified: llvm/trunk/lib/Transforms/Scalar/NewGVN.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/NewGVN.cpp?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/NewGVN.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/NewGVN.cpp Thu Mar 9 18:32:33 2017
@@ -376,9 +376,11 @@ private:
// Elimination.
struct ValueDFS;
- void convertDenseToDFSOrdered(const CongruenceClass::MemberSet &,
- SmallVectorImpl<ValueDFS> &);
- void convertDenseToLoadsAndStores(const CongruenceClass::MemberSet &,
+ void convertClassToDFSOrdered(const CongruenceClass::MemberSet &,
+ SmallVectorImpl<ValueDFS> &,
+ DenseMap<const Value *, unsigned int> &,
+ SmallPtrSetImpl<Instruction *> &);
+ void convertClassToLoadsAndStores(const CongruenceClass::MemberSet &,
SmallVectorImpl<ValueDFS> &);
bool eliminateInstructions(Function &);
@@ -2214,10 +2216,14 @@ struct NewGVN::ValueDFS {
// This function converts the set of members for a congruence class from values,
// to sets of defs and uses with associated DFS info. The total number of
-// reachable uses for each value is stored in UseCount.
-void NewGVN::convertDenseToDFSOrdered(
+// reachable uses for each value is stored in UseCount, and instructions that
+// seem
+// dead (have no non-dead uses) are stored in ProbablyDead.
+void NewGVN::convertClassToDFSOrdered(
const CongruenceClass::MemberSet &Dense,
- SmallVectorImpl<ValueDFS> &DFSOrderedSet) {
+ SmallVectorImpl<ValueDFS> &DFSOrderedSet,
+ DenseMap<const Value *, unsigned int> &UseCounts,
+ SmallPtrSetImpl<Instruction *> &ProbablyDead) {
for (auto D : Dense) {
// First add the value.
BasicBlock *BB = getBlockForValue(D);
@@ -2238,11 +2244,15 @@ void NewGVN::convertDenseToDFSOrdered(
assert(isa<Instruction>(D) &&
"The dense set member should always be an instruction");
VDDef.LocalNum = InstrDFS.lookup(D);
-
DFSOrderedSet.emplace_back(VDDef);
+ Instruction *Def = cast<Instruction>(D);
+ unsigned int UseCount = 0;
// Now add the uses.
- for (auto &U : D->uses()) {
+ for (auto &U : Def->uses()) {
if (auto *I = dyn_cast<Instruction>(U.getUser())) {
+ // Don't try to replace into dead uses
+ if (InstructionsToErase.count(I))
+ continue;
ValueDFS VDUse;
// Put the phi node uses in the incoming block.
BasicBlock *IBlock;
@@ -2265,15 +2275,24 @@ void NewGVN::convertDenseToDFSOrdered(
VDUse.DFSIn = DomNode->getDFSNumIn();
VDUse.DFSOut = DomNode->getDFSNumOut();
VDUse.U = &U;
+ ++UseCount;
DFSOrderedSet.emplace_back(VDUse);
}
}
+
+ // If there are no uses, it's probably dead (but it may have side-effects,
+ // so not definitely dead. Otherwise, store the number of uses so we can
+ // track if it becomes dead later).
+ if (UseCount == 0)
+ ProbablyDead.insert(Def);
+ else
+ UseCounts[Def] = UseCount;
}
}
// This function converts the set of members for a congruence class from values,
// to the set of defs for loads and stores, with associated DFS info.
-void NewGVN::convertDenseToLoadsAndStores(
+void NewGVN::convertClassToLoadsAndStores(
const CongruenceClass::MemberSet &Dense,
SmallVectorImpl<ValueDFS> &LoadsAndStores) {
for (auto D : Dense) {
@@ -2459,11 +2478,13 @@ bool NewGVN::eliminateInstructions(Funct
}
}
+ // Map to store the use counts
+ DenseMap<const Value *, unsigned int> UseCounts;
for (CongruenceClass *CC : reverse(CongruenceClasses)) {
// Track the equivalent store info so we can decide whether to try
// dead store elimination.
SmallVector<ValueDFS, 8> PossibleDeadStores;
-
+ SmallPtrSet<Instruction *, 8> ProbablyDead;
if (CC->Dead)
continue;
// Everything still in the INITIAL class is unreachable or dead.
@@ -2490,7 +2511,7 @@ bool NewGVN::eliminateInstructions(Funct
for (auto M : CC->Members) {
Value *Member = M;
// Void things have no uses we can replace.
- if (Member == CC->RepLeader || Member->getType()->isVoidTy()) {
+ if (Member == Leader || Member->getType()->isVoidTy()) {
MembersLeft.insert(Member);
continue;
}
@@ -2503,7 +2524,6 @@ bool NewGVN::eliminateInstructions(Funct
assert(Leader != I && "About to accidentally remove our leader");
replaceInstruction(I, Leader);
AnythingReplaced = true;
-
continue;
} else {
MembersLeft.insert(I);
@@ -2523,18 +2543,18 @@ bool NewGVN::eliminateInstructions(Funct
// Convert the members to DFS ordered sets and then merge them.
SmallVector<ValueDFS, 8> DFSOrderedSet;
- convertDenseToDFSOrdered(CC->Members, DFSOrderedSet);
+ convertClassToDFSOrdered(CC->Members, DFSOrderedSet, UseCounts,
+ ProbablyDead);
// Sort the whole thing.
std::sort(DFSOrderedSet.begin(), DFSOrderedSet.end());
for (auto &VD : DFSOrderedSet) {
int MemberDFSIn = VD.DFSIn;
int MemberDFSOut = VD.DFSOut;
- Value *Member = VD.Def;
- Use *MemberUse = VD.U;
-
+ Value *Def = VD.Def;
+ Use *U = VD.U;
// We ignore void things because we can't get a value from them.
- if (Member && Member->getType()->isVoidTy())
+ if (Def && Def->getType()->isVoidTy())
continue;
if (EliminationStack.empty()) {
@@ -2560,62 +2580,95 @@ bool NewGVN::eliminateInstructions(Funct
// start using, we also push.
// Otherwise, we walk along, processing members who are
// dominated by this scope, and eliminate them.
- bool ShouldPush = Member && EliminationStack.empty();
+ bool ShouldPush = Def && EliminationStack.empty();
bool OutOfScope =
!EliminationStack.isInScope(MemberDFSIn, MemberDFSOut);
if (OutOfScope || ShouldPush) {
// Sync to our current scope.
EliminationStack.popUntilDFSScope(MemberDFSIn, MemberDFSOut);
- bool ShouldPush = Member && EliminationStack.empty();
+ bool ShouldPush = Def && EliminationStack.empty();
if (ShouldPush) {
- EliminationStack.push_back(Member, MemberDFSIn, MemberDFSOut);
+ EliminationStack.push_back(Def, MemberDFSIn, MemberDFSOut);
}
}
- if (MemberUse) {
- // Any def or use we hit at this point must be in an instruction.
- // We assert so in convertDenseToDFSOrdered about defs, but assert
- // it here too just make sure we are consistent.
- assert(isa<Instruction>(MemberUse->get()) &&
- "Use should have been in an instruction");
- assert(isa<Instruction>(MemberUse->getUser()) &&
- "Def should have been in an instruction");
+ // Skip the Def's, we only want to eliminate on their uses. But mark
+ // dominated defs as dead.
+ if (Def) {
+ // For anything in this case, what and how we value number
+ // guarantees that any side-effets that would have occurred (ie
+ // throwing, etc) can be proven to either still occur (because it's
+ // dominated by something that has the same side-effects), or never
+ // occur. Otherwise, we would not have been able to prove it value
+ // equivalent to something else. For these things, we can just mark
+ // it all dead. Note that this is different from the "ProbablyDead"
+ // set, which may not be dominated by anything, and thus, are only
+ // easy to prove dead if they are also side-effect free.
+ if (!EliminationStack.empty() && Def != EliminationStack.back() &&
+ isa<Instruction>(Def))
+ markInstructionForDeletion(cast<Instruction>(Def));
+ continue;
+ }
+ // At this point, we know it is a Use we are trying to possibly
+ // replace.
+
+ assert(isa<Instruction>(U->get()) &&
+ "Current def should have been an instruction");
+ assert(isa<Instruction>(U->getUser()) &&
+ "Current user should have been an instruction");
+
+ // If the thing we are replacing into is already marked to be dead,
+ // this use is dead. Note that this is true regardless of whether
+ // we have anything dominating the use or not. We do this here
+ // because we are already walking all the uses anyway.
+ Instruction *InstUse = cast<Instruction>(U->getUser());
+ if (InstructionsToErase.count(InstUse)) {
+ auto &UseCount = UseCounts[U->get()];
+ if (--UseCount == 0) {
+ ProbablyDead.insert(cast<Instruction>(U->get()));
+ }
}
// If we get to this point, and the stack is empty we must have a use
- // with nothing we can use to eliminate it, just skip it.
+ // with nothing we can use to eliminate this use, so just skip it.
if (EliminationStack.empty())
continue;
- // Skip the Value's, we only want to eliminate on their uses.
- if (Member)
- continue;
Value *DominatingLeader = EliminationStack.back();
// Don't replace our existing users with ourselves.
- if (MemberUse->get() == DominatingLeader)
+ if (U->get() == DominatingLeader)
continue;
-
DEBUG(dbgs() << "Found replacement " << *DominatingLeader << " for "
- << *MemberUse->get() << " in " << *(MemberUse->getUser())
- << "\n");
+ << *U->get() << " in " << *(U->getUser()) << "\n");
// If we replaced something in an instruction, handle the patching of
- // metadata.
-
- auto *ReplacedInst = cast<Instruction>(MemberUse->get());
- // Skip this if we are replacing predicateinfo with its original
- // operand, as we already know we can just drop it.
+ // metadata. Skip this if we are replacing predicateinfo with its
+ // original operand, as we already know we can just drop it.
+ auto *ReplacedInst = cast<Instruction>(U->get());
auto *PI = PredInfo->getPredicateInfoFor(ReplacedInst);
if (!PI || DominatingLeader != PI->OriginalOp)
patchReplacementInstruction(ReplacedInst, DominatingLeader);
- MemberUse->set(DominatingLeader);
+ U->set(DominatingLeader);
+ // This is now a use of the dominating leader, which means if the
+ // dominating leader was dead, it's now live!
+ auto &LeaderUseCount = UseCounts[DominatingLeader];
+ // It's about to be alive again.
+ if (LeaderUseCount == 0 && isa<Instruction>(DominatingLeader))
+ ProbablyDead.erase(cast<Instruction>(DominatingLeader));
+ ++LeaderUseCount;
AnythingReplaced = true;
}
}
}
+ // At this point, anything still in the ProbablyDead set is actually dead if
+ // would be trivially dead.
+ for (auto *I : ProbablyDead)
+ if (wouldInstructionBeTriviallyDead(I))
+ markInstructionForDeletion(I);
+
// Cleanup the congruence class.
SmallPtrSet<Value *, 4> MembersLeft;
for (Value *Member : CC->Members) {
@@ -2624,20 +2677,13 @@ bool NewGVN::eliminateInstructions(Funct
continue;
}
- if (auto *MemberInst = dyn_cast<Instruction>(Member)) {
- if (isInstructionTriviallyDead(MemberInst)) {
- // TODO: Don't mark loads of undefs.
- markInstructionForDeletion(MemberInst);
- continue;
- }
- }
MembersLeft.insert(Member);
}
CC->Members.swap(MembersLeft);
// If we have possible dead stores to look at, try to eliminate them.
if (CC->StoreCount > 0) {
- convertDenseToLoadsAndStores(CC->Members, PossibleDeadStores);
+ convertClassToLoadsAndStores(CC->Members, PossibleDeadStores);
std::sort(PossibleDeadStores.begin(), PossibleDeadStores.end());
ValueDFSStack EliminationStack;
for (auto &VD : PossibleDeadStores) {
Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/Local.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/Local.cpp Thu Mar 9 18:32:33 2017
@@ -287,7 +287,15 @@ bool llvm::ConstantFoldTerminator(BasicB
///
bool llvm::isInstructionTriviallyDead(Instruction *I,
const TargetLibraryInfo *TLI) {
- if (!I->use_empty() || isa<TerminatorInst>(I)) return false;
+ if (!I->use_empty())
+ return false;
+ return wouldInstructionBeTriviallyDead(I, TLI);
+}
+
+bool llvm::wouldInstructionBeTriviallyDead(Instruction *I,
+ const TargetLibraryInfo *TLI) {
+ if (isa<TerminatorInst>(I))
+ return false;
// We don't want the landingpad-like instructions removed by anything this
// general.
@@ -307,7 +315,8 @@ bool llvm::isInstructionTriviallyDead(In
return true;
}
- if (!I->mayHaveSideEffects()) return true;
+ if (!I->mayHaveSideEffects())
+ return true;
// Special case intrinsics that "may have side effects" but can be deleted
// when dead.
@@ -334,7 +343,8 @@ bool llvm::isInstructionTriviallyDead(In
}
}
- if (isAllocLikeFn(I, TLI)) return true;
+ if (isAllocLikeFn(I, TLI))
+ return true;
if (CallInst *CI = isFreeCall(I, TLI))
if (Constant *C = dyn_cast<Constant>(CI->getArgOperand(0)))
Modified: llvm/trunk/test/Transforms/NewGVN/load-constant-mem.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/NewGVN/load-constant-mem.ll?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/NewGVN/load-constant-mem.ll (original)
+++ llvm/trunk/test/Transforms/NewGVN/load-constant-mem.ll Thu Mar 9 18:32:33 2017
@@ -1,21 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -basicaa -newgvn -S | FileCheck %s
; PR4189
@G = external constant [4 x i32]
define i32 @test(i8* %p, i32 %i) nounwind {
+; CHECK-LABEL: @test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P:%.*]] = getelementptr [4 x i32], [4 x i32]* @G, i32 0, i32 [[I:%.*]]
+; CHECK-NEXT: store i8 4, i8* [[P:%.*]]
+; CHECK-NEXT: ret i32 0
+;
entry:
- %P = getelementptr [4 x i32], [4 x i32]* @G, i32 0, i32 %i
- %A = load i32, i32* %P
- store i8 4, i8* %p
- %B = load i32, i32* %P
- %C = sub i32 %A, %B
- ret i32 %C
+ %P = getelementptr [4 x i32], [4 x i32]* @G, i32 0, i32 %i
+ %A = load i32, i32* %P
+ store i8 4, i8* %p
+ %B = load i32, i32* %P
+ %C = sub i32 %A, %B
+ ret i32 %C
}
-; CHECK-LABEL: define i32 @test
-; CHECK-NEXT: entry:
-; CHECK-NEXT: %P = getelementptr [4 x i32], [4 x i32]* @G, i32 0, i32 %i
-; CHECK-NEXT: %A = load i32, i32* %P
-; CHECK-NEXT: store i8 4, i8* %p
-; CHECK-NEXT: ret i32 0
-; CHECK-NEXT: }
Modified: llvm/trunk/test/Transforms/NewGVN/pr31613.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/NewGVN/pr31613.ll?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/NewGVN/pr31613.ll (original)
+++ llvm/trunk/test/Transforms/NewGVN/pr31613.ll Thu Mar 9 18:32:33 2017
@@ -85,7 +85,6 @@ define void @e() {
; CHECK: l:
; CHECK-NEXT: br label [[R:%.*]]
; CHECK: q:
-; CHECK-NEXT: [[M:%.*]] = load %struct.a*, %struct.a** null
; CHECK-NEXT: br label [[R]]
; CHECK: r:
; CHECK-NEXT: switch i32 undef, label [[N:%.*]] [
@@ -95,7 +94,6 @@ define void @e() {
; CHECK-NEXT: store i32 undef, i32* [[F]], !g !0
; CHECK-NEXT: br label [[H]]
; CHECK: n:
-; CHECK-NEXT: [[O:%.*]] = load %struct.a*, %struct.a** null
; CHECK-NEXT: ret void
;
%f = alloca i32
Modified: llvm/trunk/test/Transforms/NewGVN/pr31682.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/NewGVN/pr31682.ll?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/NewGVN/pr31682.ll (original)
+++ llvm/trunk/test/Transforms/NewGVN/pr31682.ll Thu Mar 9 18:32:33 2017
@@ -12,7 +12,6 @@ define void @bar() {
; CHECK-NEXT: [[TMP:%.*]] = load %struct.foo*, %struct.foo** @global
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_FOO:%.*]], %struct.foo* [[TMP]], i64 0, i32 1
; CHECK-NEXT: br i1 undef, label [[BB2]], label [[BB7:%.*]]
; CHECK: bb7:
; CHECK-NEXT: br label [[BB10:%.*]]
Modified: llvm/trunk/test/Transforms/NewGVN/pr31758.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/NewGVN/pr31758.ll?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/NewGVN/pr31758.ll (original)
+++ llvm/trunk/test/Transforms/NewGVN/pr31758.ll Thu Mar 9 18:32:33 2017
@@ -10,9 +10,6 @@ define void @tinkywinky() {
; CHECK-NEXT: bb:
; CHECK-NEXT: br label [[BB90:%.*]]
; CHECK: bb90:
-; CHECK-NEXT: [[TMP91:%.*]] = bitcast %struct.dipsy** undef to %struct.patatino**
-; CHECK-NEXT: [[TMP92:%.*]] = load %struct.patatino*, %struct.patatino** [[TMP91]], align 8
-; CHECK-NEXT: [[TMP136:%.*]] = load %struct.patatino*, %struct.patatino** [[TMP91]], align 8
; CHECK-NEXT: br label [[BB90]]
; CHECK: bb138:
; CHECK-NEXT: store i8 undef, i8* null
Modified: llvm/trunk/test/Transforms/NewGVN/tbaa.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/NewGVN/tbaa.ll?rev=297428&r1=297427&r2=297428&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/NewGVN/tbaa.ll (original)
+++ llvm/trunk/test/Transforms/NewGVN/tbaa.ll Thu Mar 9 18:32:33 2017
@@ -1,7 +1,4 @@
-; NewGVN lets DCE take care of the dead code
-; Some of it is gotten, some of it is not, because NewGVN does
-; not attempt to spend large amounts of time doing DCE
-; RUN: opt -tbaa -basicaa -newgvn -dce -S < %s | FileCheck %s
+; RUN: opt -tbaa -basicaa -newgvn -S < %s | FileCheck %s
define i32 @test1(i8* %p, i8* %q) {
; CHECK: @test1(i8* %p, i8* %q)
@@ -106,7 +103,7 @@ define i32 @test9(i32* %p, i32* %q) {
declare void @clobber()
-declare i32 @foo(i8*) readonly nounwind
+declare i32 @foo(i8*) readonly
; CHECK: [[TAGC]] = !{[[TYPEC:!.*]], [[TYPEC]], i64 0}
; CHECK: [[TYPEC]] = !{!"C", [[TYPEA:!.*]]}
More information about the llvm-commits
mailing list