@@ -4961,55 +4961,68 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
4961
4961
Value *
4962
4962
InstCombinerImpl::pushFreezeToPreventPoisonFromPropagating (FreezeInst &OrigFI) {
4963
4963
// 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.
4967
4967
// Op1 = ... ; Op1 can be posion
4968
- // Op0 = Inst(Op1, NonPoisonOps...) ; Op0 has only one use
4968
+ // Op0 = Inst(Op1, NonPoisonOps...)
4969
4969
// ... = Freeze(Op0)
4970
4970
// =>
4971
4971
// Op1 = ...
4972
4972
// Op1.fr = Freeze(Op1)
4973
4973
// ... = Inst(Op1.fr, NonPoisonOps...)
4974
- auto *OrigOp = OrigFI.getOperand (0 );
4975
- auto *OrigOpInst = dyn_cast<Instruction>(OrigOp);
4976
4974
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 ;
4982
4978
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 ;
4990
5001
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);
4997
5006
continue ;
4998
- MaybePoisonOperands.insert (V);
4999
- }
5007
+ }
5000
5008
5001
- OrigOpInst->dropPoisonGeneratingAnnotations ();
5009
+ auto *I = cast<Instruction>(V);
5010
+ if (!Visited.insert (I).second )
5011
+ continue ;
5002
5012
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
+ }
5006
5020
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);
5011
5023
}
5012
- return OrigOp;
5024
+
5025
+ return OrigUse->get ();
5013
5026
}
5014
5027
5015
5028
Instruction *InstCombinerImpl::foldFreezeIntoRecurrence (FreezeInst &FI,
0 commit comments