NewGVN: Fix PR 34430 - we need to look through predicateinfo copies to detect self-cycles of phi nodes. We also need to not ignore certain types of arguments when testing whether the phi has a backedge or was originally constant.

llvm-svn: 312510
This commit is contained in:
Daniel Berlin 2017-09-05 02:17:43 +00:00
parent 54a92fcc5d
commit f9c9455d3f
2 changed files with 80 additions and 31 deletions

View File

@ -851,14 +851,22 @@ void NewGVN::deleteExpression(const Expression *E) const {
ExpressionAllocator.Deallocate(E);
}
// Return true if V is really PN, even accounting for predicateinfo copies.
static bool isCopyOfSelf(const Value *V, const PHINode *PN) {
if (V == PN)
return V;
// If V is a predicateinfo copy, get the thing it is a copy of.
static Value *getCopyOf(const Value *V) {
if (auto *II = dyn_cast<IntrinsicInst>(V))
if (II->getIntrinsicID() == Intrinsic::ssa_copy && II->getOperand(0) == PN)
return true;
return false;
if (II->getIntrinsicID() == Intrinsic::ssa_copy)
return II->getOperand(0);
return nullptr;
}
// Return true if V is really PN, even accounting for predicateinfo copies.
static bool isCopyOfPHI(const Value *V, const PHINode *PN) {
return V == PN || getCopyOf(V) == PN;
}
static bool isCopyOfAPHI(const Value *V) {
auto *CO = getCopyOf(V);
return CO && isa<PHINode>(CO);
}
PHIExpression *NewGVN::createPHIExpression(Instruction *I, bool &HasBackedge,
@ -890,23 +898,21 @@ PHIExpression *NewGVN::createPHIExpression(Instruction *I, bool &HasBackedge,
// Filter out unreachable phi operands.
auto Filtered = make_filter_range(PHIOperands, [&](const Use *U) {
if (isCopyOfSelf(*U, PN))
auto *BB = PN->getIncomingBlock(*U);
if (isCopyOfPHI(*U, PN))
return false;
if (!ReachableEdges.count({PN->getIncomingBlock(*U), PHIBlock}))
if (!ReachableEdges.count({BB, PHIBlock}))
return false;
// Things in TOPClass are equivalent to everything.
if (ValueToClass.lookup(*U) == TOPClass)
return false;
OriginalOpsConstant = OriginalOpsConstant && isa<Constant>(*U);
HasBackedge = HasBackedge || isBackedge(BB, PHIBlock);
return lookupOperandLeader(*U) != PN;
});
std::transform(Filtered.begin(), Filtered.end(), op_inserter(E),
[&](const Use *U) -> Value * {
auto *BB = PN->getIncomingBlock(*U);
HasBackedge = HasBackedge || isBackedge(BB, PHIBlock);
OriginalOpsConstant =
OriginalOpsConstant && isa<Constant>(*U);
return lookupOperandLeader(*U);
});
std::transform(
Filtered.begin(), Filtered.end(), op_inserter(E),
[&](const Use *U) -> Value * { return lookupOperandLeader(*U); });
return E;
}
@ -990,7 +996,6 @@ const Expression *NewGVN::checkSimplificationResults(Expression *E,
addAdditionalUsers(V, I);
return createVariableOrConstant(CC->getLeader());
}
if (CC->getDefiningExpr()) {
// If we simplified to something else, we need to communicate
// that we're users of the value we simplified to.
@ -1611,8 +1616,9 @@ bool NewGVN::isCycleFree(const Instruction *I) const {
if (SCC.size() == 1)
InstCycleState.insert({I, ICS_CycleFree});
else {
bool AllPhis =
llvm::all_of(SCC, [](const Value *V) { return isa<PHINode>(V); });
bool AllPhis = llvm::all_of(SCC, [](const Value *V) {
return isa<PHINode>(V) || isCopyOfAPHI(V);
});
ICS = AllPhis ? ICS_CycleFree : ICS_Cycle;
for (auto *Member : SCC)
if (auto *MemberPhi = dyn_cast<PHINode>(Member))
@ -1632,9 +1638,9 @@ const Expression *NewGVN::performSymbolicPHIEvaluation(Instruction *I) const {
// This is really shorthand for "this phi cannot cycle due to forward
// change in value of the phi is guaranteed not to later change the value of
// the phi. IE it can't be v = phi(undef, v+1)
bool AllConstant = true;
auto *E =
cast<PHIExpression>(createPHIExpression(I, HasBackedge, AllConstant));
bool OriginalOpsConstant = true;
auto *E = cast<PHIExpression>(
createPHIExpression(I, HasBackedge, OriginalOpsConstant));
// We match the semantics of SimplifyPhiNode from InstructionSimplify here.
// See if all arguments are the same.
// We track if any were undef because they need special handling.
@ -1660,14 +1666,10 @@ const Expression *NewGVN::performSymbolicPHIEvaluation(Instruction *I) const {
deleteExpression(E);
return createDeadExpression();
}
unsigned NumOps = 0;
Value *AllSameValue = *(Filtered.begin());
++Filtered.begin();
// Can't use std::equal here, sadly, because filter.begin moves.
if (llvm::all_of(Filtered, [&](Value *Arg) {
++NumOps;
return Arg == AllSameValue;
})) {
if (llvm::all_of(Filtered, [&](Value *Arg) { return Arg == AllSameValue; })) {
// In LLVM's non-standard representation of phi nodes, it's possible to have
// phi nodes with cycles (IE dependent on other phis that are .... dependent
// on the original phi node), especially in weird CFG's where some arguments
@ -1682,9 +1684,8 @@ const Expression *NewGVN::performSymbolicPHIEvaluation(Instruction *I) const {
// multivalued phi, and we need to know if it's cycle free in order to
// evaluate whether we can ignore the undef. The other parts of this are
// just shortcuts. If there is no backedge, or all operands are
// constants, or all operands are ignored but the undef, it also must be
// cycle free.
if (!AllConstant && HasBackedge && NumOps > 0 &&
// constants, it also must be cycle free.
if (HasBackedge && !OriginalOpsConstant &&
!isa<UndefValue>(AllSameValue) && !isCycleFree(I))
return E;

View File

@ -0,0 +1,48 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; ModuleID = 'bugpoint-reduced-simplified.bc'
; RUN: opt < %s -newgvn -S | FileCheck %s
source_filename = "bugpoint-output-e4c7d0f.bc"
; Make sure we still properly resolve phi cycles when they involve predicateinfo copies of phis.
define void @hoge() local_unnamed_addr #0 {
; CHECK-LABEL: @hoge(
; CHECK-NEXT: bb:
; CHECK-NEXT: br i1 undef, label [[BB6:%.*]], label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br label [[BB6]]
; CHECK: bb2:
; CHECK-NEXT: br i1 true, label [[BB3:%.*]], label [[BB6]]
; CHECK: bb3:
; CHECK-NEXT: br label [[BB4:%.*]]
; CHECK: bb4:
; CHECK-NEXT: br i1 undef, label [[BB2:%.*]], label [[BB6]]
; CHECK: bb6:
; CHECK-NEXT: br label [[BB4]]
;
bb:
br i1 undef, label %bb6, label %bb1
bb1: ; preds = %bb
br label %bb6
bb2: ; preds = %bb4
%tmp = icmp slt i8 %tmp5, 7
br i1 %tmp, label %bb3, label %bb6
bb3: ; preds = %bb2
br label %bb4
bb4: ; preds = %bb6, %bb3
%tmp5 = phi i8 [ %tmp5, %bb3 ], [ %tmp7, %bb6 ]
br i1 undef, label %bb2, label %bb6
bb6: ; preds = %bb4, %bb2, %bb1, %bb
%tmp7 = phi i8 [ %tmp5, %bb4 ], [ %tmp5, %bb2 ], [ 5, %bb1 ], [ undef, %bb ]
br label %bb4
}
attributes #0 = { norecurse noreturn nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.ident = !{!0}
!0 = !{!"clang version 6.0.0 (http://llvm.org/git/clang.git e649d902285b23af8ba58cb92a739f3bad2723df) (/Users/dannyb/sources/llvm-clean 0abfd30028cbb294ff2c2dd5e2df4ec3fdb6c591)"}