NewGVN: Fix PR 33185 by checking whether we need to recursively
generate a phi of ops, which we don't currently support. llvm-svn: 304272
This commit is contained in:
parent
9ceafe267b
commit
be3e7ba45e
|
@ -613,7 +613,7 @@ private:
|
||||||
return CClass;
|
return CClass;
|
||||||
}
|
}
|
||||||
void initializeCongruenceClasses(Function &F);
|
void initializeCongruenceClasses(Function &F);
|
||||||
const Expression *makePossiblePhiOfOps(Instruction *, bool,
|
const Expression *makePossiblePhiOfOps(Instruction *,
|
||||||
SmallPtrSetImpl<Value *> &);
|
SmallPtrSetImpl<Value *> &);
|
||||||
void addPhiOfOps(PHINode *Op, BasicBlock *BB, Instruction *ExistingValue);
|
void addPhiOfOps(PHINode *Op, BasicBlock *BB, Instruction *ExistingValue);
|
||||||
|
|
||||||
|
@ -1937,7 +1937,8 @@ void NewGVN::touchAndErase(Map &M, const KeyType &Key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewGVN::addAdditionalUsers(Value *To, Value *User) const {
|
void NewGVN::addAdditionalUsers(Value *To, Value *User) const {
|
||||||
AdditionalUsers[To].insert(User);
|
if (isa<Instruction>(To))
|
||||||
|
AdditionalUsers[To].insert(User);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewGVN::markUsersTouched(Value *V) {
|
void NewGVN::markUsersTouched(Value *V) {
|
||||||
|
@ -2423,7 +2424,7 @@ static bool okayForPHIOfOps(const Instruction *I) {
|
||||||
// When we see an instruction that is an op of phis, generate the equivalent phi
|
// When we see an instruction that is an op of phis, generate the equivalent phi
|
||||||
// of ops form.
|
// of ops form.
|
||||||
const Expression *
|
const Expression *
|
||||||
NewGVN::makePossiblePhiOfOps(Instruction *I, bool HasBackedge,
|
NewGVN::makePossiblePhiOfOps(Instruction *I,
|
||||||
SmallPtrSetImpl<Value *> &Visited) {
|
SmallPtrSetImpl<Value *> &Visited) {
|
||||||
if (!okayForPHIOfOps(I))
|
if (!okayForPHIOfOps(I))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2438,24 +2439,6 @@ NewGVN::makePossiblePhiOfOps(Instruction *I, bool HasBackedge,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
unsigned IDFSNum = InstrToDFSNum(I);
|
unsigned IDFSNum = InstrToDFSNum(I);
|
||||||
// Pretty much all of the instructions we can convert to phi of ops over a
|
|
||||||
// backedge that are adds, are really induction variables, and those are
|
|
||||||
// pretty much pointless to convert. This is very coarse-grained for a
|
|
||||||
// test, so if we do find some value, we can change it later.
|
|
||||||
// But otherwise, what can happen is we convert the induction variable from
|
|
||||||
//
|
|
||||||
// i = phi (0, tmp)
|
|
||||||
// tmp = i + 1
|
|
||||||
//
|
|
||||||
// to
|
|
||||||
// i = phi (0, tmpphi)
|
|
||||||
// tmpphi = phi(1, tmpphi+1)
|
|
||||||
//
|
|
||||||
// Which we don't want to happen. We could just avoid this for all non-cycle
|
|
||||||
// free phis, and we made go that route.
|
|
||||||
if (HasBackedge && I->getOpcode() == Instruction::Add)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
SmallPtrSet<const Value *, 8> ProcessedPHIs;
|
SmallPtrSet<const Value *, 8> ProcessedPHIs;
|
||||||
// TODO: We don't do phi translation on memory accesses because it's
|
// TODO: We don't do phi translation on memory accesses because it's
|
||||||
// complicated. For a load, we'd need to be able to simulate a new memoryuse,
|
// complicated. For a load, we'd need to be able to simulate a new memoryuse,
|
||||||
|
@ -2470,6 +2453,16 @@ NewGVN::makePossiblePhiOfOps(Instruction *I, bool HasBackedge,
|
||||||
|
|
||||||
// Convert op of phis to phi of ops
|
// Convert op of phis to phi of ops
|
||||||
for (auto &Op : I->operands()) {
|
for (auto &Op : I->operands()) {
|
||||||
|
// TODO: We can't handle expressions that must be recursively translated
|
||||||
|
// IE
|
||||||
|
// a = phi (b, c)
|
||||||
|
// f = use a
|
||||||
|
// g = f + phi of something
|
||||||
|
// To properly make a phi of ops for g, we'd have to properly translate and
|
||||||
|
// use the instruction for f. We should add this by splitting out the
|
||||||
|
// instruction creation we do below.
|
||||||
|
if (isa<Instruction>(Op) && PHINodeUses.count(cast<Instruction>(Op)))
|
||||||
|
return nullptr;
|
||||||
if (!isa<PHINode>(Op))
|
if (!isa<PHINode>(Op))
|
||||||
continue;
|
continue;
|
||||||
auto *OpPHI = cast<PHINode>(Op);
|
auto *OpPHI = cast<PHINode>(Op);
|
||||||
|
@ -2782,8 +2775,7 @@ void NewGVN::valueNumberInstruction(Instruction *I) {
|
||||||
// Make a phi of ops if necessary
|
// Make a phi of ops if necessary
|
||||||
if (Symbolized && !isa<ConstantExpression>(Symbolized) &&
|
if (Symbolized && !isa<ConstantExpression>(Symbolized) &&
|
||||||
!isa<VariableExpression>(Symbolized) && PHINodeUses.count(I)) {
|
!isa<VariableExpression>(Symbolized) && PHINodeUses.count(I)) {
|
||||||
// FIXME: Backedge argument
|
auto *PHIE = makePossiblePhiOfOps(I, Visited);
|
||||||
auto *PHIE = makePossiblePhiOfOps(I, false, Visited);
|
|
||||||
if (PHIE)
|
if (PHIE)
|
||||||
Symbolized = PHIE;
|
Symbolized = PHIE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||||
|
; RUN: opt -newgvn -S %s | FileCheck %s
|
||||||
|
|
||||||
|
@a = local_unnamed_addr global i32 9, align 4
|
||||||
|
@.str4 = private unnamed_addr constant [6 x i8] c"D:%d\0A\00", align 1
|
||||||
|
|
||||||
|
define i32 @main() local_unnamed_addr {
|
||||||
|
; CHECK-LABEL: @main(
|
||||||
|
; CHECK-NEXT: entry:
|
||||||
|
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* @a, align 4
|
||||||
|
; CHECK-NEXT: [[CMP1_I:%.*]] = icmp ne i32 [[TMP]], 0
|
||||||
|
; CHECK-NEXT: br label [[FOR_BODY_I:%.*]]
|
||||||
|
; CHECK: for.body.i:
|
||||||
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[COND_END_I:%.*]] ]
|
||||||
|
; CHECK-NEXT: [[F_08_I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC_I:%.*]], [[COND_END_I]] ]
|
||||||
|
; CHECK-NEXT: [[MUL_I:%.*]] = select i1 [[CMP1_I]], i32 [[F_08_I]], i32 0
|
||||||
|
; CHECK-NEXT: br i1 [[TMP1]], label [[COND_END_I]], label [[COND_TRUE_I:%.*]]
|
||||||
|
; CHECK: cond.true.i:
|
||||||
|
; CHECK-NEXT: [[DIV_I:%.*]] = udiv i32 [[MUL_I]], [[F_08_I]]
|
||||||
|
; CHECK-NEXT: br label [[COND_END_I]]
|
||||||
|
; CHECK: cond.end.i:
|
||||||
|
; CHECK-NEXT: [[COND_I:%.*]] = phi i32 [ [[DIV_I]], [[COND_TRUE_I]] ], [ 0, [[FOR_BODY_I]] ]
|
||||||
|
; CHECK-NEXT: [[INC_I]] = add nuw nsw i32 [[F_08_I]], 1
|
||||||
|
; CHECK-NEXT: [[EXITCOND_I:%.*]] = icmp eq i32 [[INC_I]], 4
|
||||||
|
; CHECK-NEXT: br i1 [[EXITCOND_I]], label [[FN1_EXIT:%.*]], label [[FOR_BODY_I]]
|
||||||
|
; CHECK: fn1.exit:
|
||||||
|
; CHECK-NEXT: [[CALL4:%.*]] = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str4, i64 0, i64 0), i32 [[COND_I]])
|
||||||
|
; CHECK-NEXT: ret i32 0
|
||||||
|
;
|
||||||
|
entry:
|
||||||
|
%tmp = load i32, i32* @a, align 4
|
||||||
|
%cmp1.i = icmp ne i32 %tmp, 0
|
||||||
|
br label %for.body.i
|
||||||
|
|
||||||
|
for.body.i:
|
||||||
|
%tmp1 = phi i1 [ true, %entry ], [ false, %cond.end.i ]
|
||||||
|
%f.08.i = phi i32 [ 0, %entry ], [ %inc.i, %cond.end.i ]
|
||||||
|
%mul.i = select i1 %cmp1.i, i32 %f.08.i, i32 0
|
||||||
|
br i1 %tmp1, label %cond.end.i, label %cond.true.i
|
||||||
|
|
||||||
|
cond.true.i:
|
||||||
|
;; Ensure we don't replace this divide with a phi of ops that merges the wrong loop iteration value
|
||||||
|
%div.i = udiv i32 %mul.i, %f.08.i
|
||||||
|
br label %cond.end.i
|
||||||
|
|
||||||
|
cond.end.i:
|
||||||
|
%cond.i = phi i32 [ %div.i, %cond.true.i ], [ 0, %for.body.i ]
|
||||||
|
%inc.i = add nuw nsw i32 %f.08.i, 1
|
||||||
|
%exitcond.i = icmp eq i32 %inc.i, 4
|
||||||
|
br i1 %exitcond.i, label %fn1.exit, label %for.body.i
|
||||||
|
|
||||||
|
fn1.exit:
|
||||||
|
%cond.i.lcssa = phi i32 [ %cond.i, %cond.end.i ]
|
||||||
|
%call4= tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str4, i64 0, i64 0), i32 %cond.i.lcssa)
|
||||||
|
ret i32 0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @printf(i8* nocapture readonly, ...)
|
||||||
|
|
Loading…
Reference in New Issue