Skip to content

Commit 9954c97

Browse files
committed
Do single pass recursive propagation
1 parent f6d2a51 commit 9954c97

File tree

1 file changed

+48
-35
lines changed

1 file changed

+48
-35
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4961,55 +4961,68 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
49614961
Value *
49624962
InstCombinerImpl::pushFreezeToPreventPoisonFromPropagating(FreezeInst &OrigFI) {
49634963
// Try to push freeze through instructions that propagate but don't produce
4964-
// poison as far as possible. If an operand of freeze is one-use and does
4965-
// not produce poison then push the freeze through to the operands that are
4966-
// not guaranteed non-poison. The actual transform is as follows.
4964+
// poison as far as possible. If an operand of freeze does not produce poison
4965+
// then push the freeze through to the operands that are not guaranteed
4966+
// non-poison. The actual transform is as follows.
49674967
// Op1 = ... ; Op1 can be posion
4968-
// Op0 = Inst(Op1, NonPoisonOps...) ; Op0 has only one use
4968+
// Op0 = Inst(Op1, NonPoisonOps...)
49694969
// ... = Freeze(Op0)
49704970
// =>
49714971
// Op1 = ...
49724972
// Op1.fr = Freeze(Op1)
49734973
// ... = Inst(Op1.fr, NonPoisonOps...)
4974-
auto *OrigOp = OrigFI.getOperand(0);
4975-
auto *OrigOpInst = dyn_cast<Instruction>(OrigOp);
49764974

4977-
// While we could change the other users of OrigOp to use freeze(OrigOp), that
4978-
// potentially reduces their optimization potential, so let's only do this iff
4979-
// the OrigOp is only used by the freeze.
4980-
if (!OrigOpInst || !OrigOpInst->hasOneUse() || isa<PHINode>(OrigOp))
4981-
return nullptr;
4975+
auto CanPushFreeze = [](Value *V) {
4976+
if (!isa<Instruction>(V) || isa<PHINode>(V))
4977+
return false;
49824978

4983-
// We can't push the freeze through an instruction which can itself create
4984-
// poison. If the only source of new poison is flags, we can simply
4985-
// strip them (since we know the only use is the freeze and nothing can
4986-
// benefit from them.)
4987-
if (canCreateUndefOrPoison(cast<Operator>(OrigOp),
4988-
/*ConsiderFlagsAndMetadata*/ false))
4989-
return nullptr;
4979+
// We can't push the freeze through an instruction which can itself create
4980+
// poison. If the only source of new poison is flags, we can simply
4981+
// strip them (since we know the only use is the freeze and nothing can
4982+
// benefit from them.)
4983+
return !canCreateUndefOrPoison(cast<Operator>(V),
4984+
/*ConsiderFlagsAndMetadata*/ false);
4985+
};
4986+
4987+
// Pushing freezes up long instruction chains can be expensive. Instead,
4988+
// we directly push the freeze all the way to the leaves. However, we leave
4989+
// deduplication of freezes on the same value for freezeOtherUses().
4990+
Use *OrigUse = &OrigFI.getOperandUse(0);
4991+
SmallPtrSet<Instruction *, 8> Visited;
4992+
SmallVector<Use *, 8> Worklist;
4993+
Worklist.push_back(OrigUse);
4994+
while (!Worklist.empty()) {
4995+
auto *U = Worklist.pop_back_val();
4996+
Value *V = U->get();
4997+
if (!CanPushFreeze(V)) {
4998+
// If we can't push through the original instruction, abort the transform.
4999+
if (U == OrigUse)
5000+
return nullptr;
49905001

4991-
// If operand is guaranteed not to be poison, there is no need to add freeze
4992-
// to the operand. So we first find the operand that is not guaranteed to be
4993-
// poison.
4994-
SmallSetVector<Value *, 4> MaybePoisonOperands;
4995-
for (Value *V : OrigOpInst->operands()) {
4996-
if (isa<MetadataAsValue>(V) || isGuaranteedNotToBeUndefOrPoison(V))
5002+
auto *UserI = cast<Instruction>(U->getUser());
5003+
Builder.SetInsertPoint(UserI);
5004+
Value *Frozen = Builder.CreateFreeze(V, V->getName() + ".fr");
5005+
U->set(Frozen);
49975006
continue;
4998-
MaybePoisonOperands.insert(V);
4999-
}
5007+
}
50005008

5001-
OrigOpInst->dropPoisonGeneratingAnnotations();
5009+
auto *I = cast<Instruction>(V);
5010+
if (!Visited.insert(I).second)
5011+
continue;
50025012

5003-
// If all operands are guaranteed to be non-poison, we can drop freeze.
5004-
if (MaybePoisonOperands.empty())
5005-
return OrigOp;
5013+
// reverse() to emit freezes in a more natural order.
5014+
for (Use &Op : reverse(I->operands())) {
5015+
Value *OpV = Op.get();
5016+
if (isa<MetadataAsValue>(OpV) || isGuaranteedNotToBeUndefOrPoison(OpV))
5017+
continue;
5018+
Worklist.push_back(&Op);
5019+
}
50065020

5007-
Builder.SetInsertPoint(OrigOpInst);
5008-
for (Value *V : MaybePoisonOperands) {
5009-
Value *Frozen = Builder.CreateFreeze(V, V->getName() + ".fr");
5010-
OrigOpInst->replaceUsesOfWith(V, Frozen);
5021+
I->dropPoisonGeneratingAnnotations();
5022+
this->Worklist.add(I);
50115023
}
5012-
return OrigOp;
5024+
5025+
return OrigUse->get();
50135026
}
50145027

50155028
Instruction *InstCombinerImpl::foldFreezeIntoRecurrence(FreezeInst &FI,

0 commit comments

Comments
 (0)