Index: llvm/lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -172,7 +172,7 @@ Instruction *visitLandingPadInst(LandingPadInst &LI); Instruction *visitVAEndInst(VAEndInst &I); Value *pushFreezeToPreventPoisonFromPropagating(FreezeInst &FI); - bool freezeDominatedUses(FreezeInst &FI); + bool freezeOtherUses(FreezeInst &FI); Instruction *visitFreeze(FreezeInst &I); /// Specify what to return for unhandled instructions. Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3807,20 +3807,41 @@ return OrigOp; } -bool InstCombinerImpl::freezeDominatedUses(FreezeInst &FI) { +bool InstCombinerImpl::freezeOtherUses(FreezeInst &FI) { Value *Op = FI.getOperand(0); - if (isa(Op)) + if (isa(Op) || Op->hasOneUse()) return false; - bool Changed = false; + // Find the nearest common dominator of all uses of Op. + Instruction *Dom = nullptr; + for (Use &U : Op->uses()) { + Instruction *I = cast(U.getUser()); + if (auto *PHI = dyn_cast(I)) + I = PHI->getIncomingBlock(U)->getTerminator(); + + if (!Dom || DT.dominates(I, Dom)) + Dom = I; + else if (!DT.dominates(Dom, I)) + Dom = DT.findNearestCommonDominator(Dom->getParent(), I->getParent()) + ->getTerminator(); + } + + // This can happen if the result of an invoke is frozen and also used in + // a phi node on the normal destination. There is no dominating place to + // insert the freeze instruction in that case. + if (Dom == Op) + return false; + + // Move the freeze before the nearest common dominator. + if (!DT.dominates(&FI, Dom)) + FI.moveBefore(Dom); + Op->replaceUsesWithIf(&FI, [&](Use &U) -> bool { - bool Dominates = DT.dominates(&FI, U); - Changed |= Dominates; - return Dominates; + return U.getUser() != &FI; }); - return Changed; + return true; } Instruction *InstCombinerImpl::visitFreeze(FreezeInst &I) { @@ -3879,8 +3900,8 @@ return replaceInstUsesWith(I, Constant::replaceUndefsWith(C, ReplaceC)); } - // Replace all dominated uses of Op to freeze(Op). - if (freezeDominatedUses(I)) + // Replace uses of Op with freeze(Op). + if (freezeOtherUses(I)) return &I; return nullptr; Index: llvm/test/Transforms/InstCombine/freeze.ll =================================================================== --- llvm/test/Transforms/InstCombine/freeze.ll +++ llvm/test/Transforms/InstCombine/freeze.ll @@ -161,16 +161,16 @@ ; CHECK-LABEL: @freeze_dominated_uses_test2( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @use_i32(i32 0) -; CHECK-NEXT: call void @use_i32(i32 [[V:%.*]]) -; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[V]], 0 +; CHECK-NEXT: [[V_FR:%.*]] = freeze i32 [[V:%.*]] +; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[V_FR]], 0 ; CHECK-NEXT: br i1 [[COND]], label [[BB0:%.*]], label [[BB1:%.*]] ; CHECK: bb0: -; CHECK-NEXT: [[V_FR:%.*]] = freeze i32 [[V]] ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: bb1: -; CHECK-NEXT: call void @use_i32(i32 [[V]]) +; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: ret void @@ -235,13 +235,13 @@ define i32 @freeze_use_in_different_branches(i1 %c, i32 %x) { ; CHECK-LABEL: @freeze_use_in_different_branches( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X:%.*]] ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: call void @use_i32(i32 [[X:%.*]]) +; CHECK-NEXT: call void @use_i32(i32 [[FR]]) ; CHECK-NEXT: ret i32 0 ; CHECK: else: -; CHECK-NEXT: call void @use_i32(i32 [[X]]) -; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] +; CHECK-NEXT: call void @use_i32(i32 [[FR]]) ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) ; CHECK-NEXT: ret i32 1 ; @@ -262,12 +262,12 @@ define i32 @freeze_phi_use(i1 %c, i32 %x) { ; CHECK-LABEL: @freeze_phi_use( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X:%.*]] ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]] ; CHECK: if: ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: -; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[X:%.*]], [[IF]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[FR]], [[IF]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) ; CHECK-NEXT: ret i32 [[PHI]] ; @@ -318,13 +318,10 @@ define i1 @combine_and_after_freezing_uses(i32 %x) { ; CHECK-LABEL: @combine_and_after_freezing_uses( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[X:%.*]], 4 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[AND1]], 0 -; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[X_FR]], 11 -; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[AND2]], 11 -; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[AND]] +; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X_FR]], 15 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 15 +; CHECK-NEXT: ret i1 [[TMP2]] ; %and1 = and i32 %x, 4 %cmp1 = icmp ne i32 %and1, 0 Index: llvm/test/Transforms/InstCombine/onehot_merge.ll =================================================================== --- llvm/test/Transforms/InstCombine/onehot_merge.ll +++ llvm/test/Transforms/InstCombine/onehot_merge.ll @@ -775,8 +775,8 @@ ; CHECK-LABEL: @foo1_and_extra_use_shl2_logical( ; CHECK-NEXT: [[T0:%.*]] = shl i32 1, [[C1:%.*]] ; CHECK-NEXT: [[T1:%.*]] = shl i32 1, [[C2:%.*]] -; CHECK-NEXT: store i32 [[T1]], i32* [[P:%.*]], align 4 ; CHECK-NEXT: [[TMP1:%.*]] = freeze i32 [[T1]] +; CHECK-NEXT: store i32 [[TMP1]], i32* [[P:%.*]], align 4 ; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[T0]], [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[K:%.*]] ; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], [[TMP2]] @@ -820,9 +820,9 @@ ; CHECK-LABEL: @foo1_and_extra_use_and2_logical( ; CHECK-NEXT: [[T0:%.*]] = shl i32 1, [[C1:%.*]] ; CHECK-NEXT: [[T1:%.*]] = shl i32 1, [[C2:%.*]] -; CHECK-NEXT: [[T4:%.*]] = and i32 [[T1]], [[K:%.*]] -; CHECK-NEXT: store i32 [[T4]], i32* [[P:%.*]], align 4 ; CHECK-NEXT: [[TMP1:%.*]] = freeze i32 [[T1]] +; CHECK-NEXT: [[T4:%.*]] = and i32 [[TMP1]], [[K:%.*]] +; CHECK-NEXT: store i32 [[T4]], i32* [[P:%.*]], align 4 ; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[T0]], [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[K]] ; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], [[TMP2]] @@ -867,10 +867,10 @@ ; CHECK-LABEL: @foo1_and_extra_use_cmp2_logical( ; CHECK-NEXT: [[T0:%.*]] = shl i32 1, [[C1:%.*]] ; CHECK-NEXT: [[T1:%.*]] = shl i32 1, [[C2:%.*]] -; CHECK-NEXT: [[T4:%.*]] = and i32 [[T1]], [[K:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = freeze i32 [[T1]] +; CHECK-NEXT: [[T4:%.*]] = and i32 [[TMP1]], [[K:%.*]] ; CHECK-NEXT: [[T5:%.*]] = icmp eq i32 [[T4]], 0 ; CHECK-NEXT: store i1 [[T5]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[TMP1:%.*]] = freeze i32 [[T1]] ; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[T0]], [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[K]] ; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], [[TMP2]]