@@ -4961,55 +4961,68 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
49614961Value *
49624962InstCombinerImpl::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
50155028Instruction *InstCombinerImpl::foldFreezeIntoRecurrence (FreezeInst &FI,
0 commit comments