diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -168,7 +168,7 @@ Instruction *visitExtractValueInst(ExtractValueInst &EV); Instruction *visitLandingPadInst(LandingPadInst &LI); Instruction *visitVAEndInst(VAEndInst &I); - Value *PushFreezeToPreventPoisonFromPropagate(FreezeInst& FI); + Value *PushFreezeToPreventPoisonFromPropagate(FreezeInst &FI); Instruction *visitFreeze(FreezeInst &I); /// Specify what to return for unhandled instructions. diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3513,14 +3513,15 @@ return nullptr; } -Value *InstCombinerImpl::PushFreezeToPreventPoisonFromPropagate(FreezeInst& OrigFI) { +Value * +InstCombinerImpl::PushFreezeToPreventPoisonFromPropagate(FreezeInst &OrigFI) { // Try to push freeze through instructions that propagate but don't produce // poison as far as possible. If operand of freeze follows three conditions // 1) one-use, 2) does not produce poison and 3) has all but one // guaranteed-non-poison operands then push the freeze through to the one // operand that is not guaranteed non poison. The actual transform is as // follows. - // Op1 = ... ; ; Op1 can be posion + // Op1 = ... ; Op1 can be posion // Op0 = Inst(Op1, NonPoisonOps...) ; Op0 has only one use and only have // ; single guaranteed-non-poison operands // ... = Freeze(Op0) @@ -3528,31 +3529,42 @@ // Op1 = ... // Op1.fr = Freeze(Op1) // ... = Inst(Op1.fr, NonPoisonOps...) - auto* OrigOp = OrigFI.getOperand(0); - if (auto *OrigOpInst = dyn_cast(OrigOp)) { - if (OrigOpInst->hasOneUse() && !canCreateUndefOrPoison(dyn_cast(OrigOp))) { - Optional MaybePoisonOperand; - for (Use &U : OrigOpInst->operands()) { - if (isGuaranteedNotToBeUndefOrPoison(U.get())) - continue; - if (!MaybePoisonOperand) - MaybePoisonOperand = &U; - else if(MaybePoisonOperand) - return nullptr; - } + auto *OrigOp = OrigFI.getOperand(0); + auto *OrigOpInst = dyn_cast(OrigOp); + + // If OrigOp has multiple uses, multiple freeze will be inserted. To prevent a + // chain of freeze from being generated by a newly created freeze, we only + // consider the case of single use. + if (!OrigOpInst || !OrigOpInst->hasOneUse() || + canCreateUndefOrPoison(dyn_cast(OrigOp))) + return nullptr; - if (!MaybePoisonOperand.hasValue()) - return nullptr; + // If operand is guaranteed not to be poison, there is no need to add freeze + // to the operand. So we first find the operand that is not guaranteed to be + // poison. + Use *MaybePoisonOperand = nullptr; + for (Use &U : OrigOpInst->operands()) { + if (isGuaranteedNotToBeUndefOrPoison(U.get())) + continue; + if (!MaybePoisonOperand) + MaybePoisonOperand = &U; + else + return nullptr; + } - auto *MaybePoisonUse = MaybePoisonOperand.getValue(); - auto *FrozenMaybePoisonOperand = new FreezeInst(MaybePoisonUse->get(), MaybePoisonUse->getUser()->getName() + ".fr"); + // If all operands are guaranteed to be non-poison, we can drop freeze. + if (!MaybePoisonOperand) + return OrigOp; - replaceUse(*MaybePoisonUse, FrozenMaybePoisonOperand); - FrozenMaybePoisonOperand->insertBefore(OrigOpInst); - return OrigOp; - } - } - return nullptr; + auto *FrozenMaybePoisonOperand = new FreezeInst( + MaybePoisonOperand->get(), MaybePoisonOperand->get()->getName() + ".fr"); + + // We already folded "freeze (phi const, x)" to "phi const, (freeze x)" + assert(!isa(OrigOp)); + + replaceUse(*MaybePoisonOperand, FrozenMaybePoisonOperand); + FrozenMaybePoisonOperand->insertBefore(OrigOpInst); + return OrigOp; } Instruction *InstCombinerImpl::visitFreeze(FreezeInst &I) { diff --git a/llvm/test/Transforms/InstCombine/freeze.ll b/llvm/test/Transforms/InstCombine/freeze.ll --- a/llvm/test/Transforms/InstCombine/freeze.ll +++ b/llvm/test/Transforms/InstCombine/freeze.ll @@ -118,3 +118,20 @@ %cond.fr = freeze i1 %cond ret i1 %cond.fr } + +; add can overflows, so we cannot move freeze beyond add + +define i32 @early_freeze_test3(i32 %v1) { +; CHECK-LABEL: @early_freeze_test3( +; CHECK-NEXT: [[V2:%.*]] = shl i32 [[V1:%.*]], 1 +; CHECK-NEXT: [[V3:%.*]] = add nuw i32 [[V2]], 2 +; CHECK-NEXT: [[V3_FR:%.*]] = freeze i32 [[V3]] +; CHECK-NEXT: [[V4:%.*]] = or i32 [[V3_FR]], 1 +; CHECK-NEXT: ret i32 [[V4]] +; + %v2 = shl i32 %v1, 1 + %v3 = add nuw i32 %v2, 2 + %v4 = or i32 %v3, 1 + %v4.fr = freeze i32 %v4 + ret i32 %v4.fr +}