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); + bool freezeDominatedUses(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 @@ -3589,12 +3589,34 @@ return OrigOp; } +bool InstCombinerImpl::freezeDominatedUses(FreezeInst &FI) { + Value *Op = dyn_cast(FI.getOperand(0)); + + SmallVector UsesToBeUpdated; + for (auto &U : Op->uses()) + if (dyn_cast(U.getUser()) && + DT.dominates(dyn_cast(&FI), dyn_cast(U.getUser()))) + UsesToBeUpdated.push_back(&U); + + if (UsesToBeUpdated.size() == 0) + return false; + + for (auto *U : UsesToBeUpdated) + replaceUse(*U, dyn_cast(&FI)); + + return true; +} + Instruction *InstCombinerImpl::visitFreeze(FreezeInst &I) { Value *Op0 = I.getOperand(0); if (Value *V = SimplifyFreezeInst(Op0, SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); + // Replace all dominated uses of Op to freeze(Op). + if (freezeDominatedUses(I)) + return &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 @@ -43,7 +43,7 @@ define i32 @or_freeze_undef(i32 %x) { ; CHECK-LABEL: @or_freeze_undef( -; CHECK-NEXT: ret i32 -1 +; CHECK-NEXT: ret i32 [[X:%.*]] ; %f = freeze i32 undef %res = or i32 %x, %f @@ -135,3 +135,55 @@ %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 @freeze_dominated_uses_test1(i32 %arg) { +; CHECK-LABEL: @freeze_dominated_uses_test1( +; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR]]) +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR]]) +; CHECK-NEXT: ret void +; + %arg.fr = freeze i32 %arg + call void @use_i32(i32 %arg) + call void @use_i32(i32 %arg.fr) + ret void +} + +define void @freeze_dominated_uses_test2(i32 %arg) { +; CHECK-LABEL: @freeze_dominated_uses_test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @use_i32(i32 [[ARG:%.*]]) +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[ARG]], 0 +; CHECK-NEXT: br i1 [[COND]], label [[BB0:%.*]], label [[BB1:%.*]] +; CHECK: bb0: +; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG]] +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR]]) +; CHECK-NEXT: call void @use_i32(i32 [[ARG_FR]]) +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: bb1: +; CHECK-NEXT: call void @use_i32(i32 [[ARG]]) +; 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) + call void @use_i32(i32 %arg) + br label %end + +bb1: + call void @use_i32(i32 %arg) + br label %end + +end: + ret void +}