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 @@ -169,6 +169,7 @@ Instruction *visitLandingPadInst(LandingPadInst &LI); Instruction *visitVAEndInst(VAEndInst &I); Value *pushFreezeToPreventPoisonFromPropagating(FreezeInst &FI); + Instruction *freezeAllUsesOfArgument(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 @@ -3570,12 +3570,43 @@ return OrigOp; } +Instruction *InstCombinerImpl::freezeAllUsesOfArgument(FreezeInst &FI) { + Argument *Arg = dyn_cast(FI.getOperand(0)); + assert(Arg && "expected an argument"); + + Instruction *InsertBefore = nullptr; + for (auto *U : Arg->users()) { + auto *UI = dyn_cast(U); + if (!UI) + continue; + + auto *BB = UI->getParent(); + if (!BB->isEntryBlock()) + continue; + + if (!InsertBefore || DT.dominates(UI, InsertBefore)) + InsertBefore = UI; + } + if (!InsertBefore) + InsertBefore = FI.getFunction()->getEntryBlock().getTerminator(); + + FreezeInst *NewFI = new FreezeInst(PoisonValue::get(Arg->getType()), + Arg->getName() + ".fr", InsertBefore); + Arg->replaceAllUsesWith(NewFI); + NewFI->setOperand(0, Arg); + return replaceInstUsesWith(FI, NewFI); +} + Instruction *InstCombinerImpl::visitFreeze(FreezeInst &I) { Value *Op0 = I.getOperand(0); if (Value *V = SimplifyFreezeInst(Op0, SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); + // If I is freeze(arg), replace all uses of arg to freeze(arg). + if (dyn_cast(Op0) && !Op0->hasOneUse()) + return freezeAllUsesOfArgument(I); + // freeze (phi const, x) --> phi const, (freeze x) if (auto *PN = dyn_cast(Op0)) { if (Instruction *NV = foldOpIntoPhi(I, PN)) 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 @@ -135,3 +135,53 @@ %v4.fr = freeze i32 %v4 ret i32 %v4.fr } + +; If freeze is applied to function argument, replace all +; uses of arg to freeze(arg). + +define void @argument_freeze_test1(i32 %arg) { +; CHECK-LABEL: @argument_freeze_test1( +; CHECK-NEXT: [[ARG_FR1:%.*]] = freeze i32 [[ARG:%.*]] +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR1]]) +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR1]]) +; CHECK-NEXT: ret void +; + call void @use_i32(i32 %arg) + %arg.fr = freeze i32 %arg + call void @use_i32(i32 %arg.fr) + ret void +} + +define void @argument_freeze_test2(i32 %arg) { +; CHECK-LABEL: @argument_freeze_test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ARG_FR1:%.*]] = freeze i32 [[ARG:%.*]] +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR1]]) +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[ARG_FR1]], 0 +; CHECK-NEXT: br i1 [[COND]], label [[BB0:%.*]], label [[BB1:%.*]] +; CHECK: bb0: +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR1]]) +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: bb1: +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR1]]) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + call void @use_i32(i32 %arg) + %cond = icmp eq i32 %arg, 0 + br i1 %cond, label %bb0, label %bb1 + +bb0: + %arg.fr = freeze i32 %arg + call void @use_i32(i32 %arg.fr) + br label %end + +bb1: + call void @use_i32(i32 %arg) + br label %end + +end: + ret void +}