diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -692,6 +692,24 @@ return true; } + // Handle Freeze instructions, in a manner similar to Cast. + if (FreezeInst *FI = dyn_cast(I)) { + Value *Source = FI->getOperand(0); + if (!isa(Source) && !isa(Source)) + return false; + ComputeValueKnownInPredecessorsImpl(Source, BB, Result, Preference, + RecursionSet, CxtI); + + for (unsigned i = 0; i < Result.size(); ++i) { + if (!isGuaranteedNotToBeUndefOrPoison(Result[i].first)) { + Result.erase(Result.begin() + i); + i--; + } + } + + return !Result.empty(); + } + // Handle some boolean conditions. if (I->getType()->getPrimitiveSizeInBits() == 1) { assert(Preference == WantInteger && "One-bit non-integer type?"); diff --git a/llvm/test/Transforms/JumpThreading/freeze.ll b/llvm/test/Transforms/JumpThreading/freeze.ll --- a/llvm/test/Transforms/JumpThreading/freeze.ll +++ b/llvm/test/Transforms/JumpThreading/freeze.ll @@ -7,23 +7,14 @@ define i32 @test1(i1 %cond) { ; CHECK-LABEL: @test1( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[T1:%.*]], label [[F1:%.*]] -; CHECK: T1: -; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() -; CHECK-NEXT: br label [[MERGE:%.*]] -; CHECK: F1: -; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() -; CHECK-NEXT: br label [[MERGE]] -; CHECK: Merge: -; CHECK-NEXT: [[A:%.*]] = phi i1 [ true, [[T1]] ], [ false, [[F1]] ] -; CHECK-NEXT: [[B:%.*]] = phi i32 [ [[V1]], [[T1]] ], [ [[V2]], [[F1]] ] -; CHECK-NEXT: [[A_FR:%.*]] = freeze i1 [[A]] -; CHECK-NEXT: br i1 [[A_FR]], label [[T2:%.*]], label [[F2:%.*]] +; CHECK-NEXT: br i1 [[COND:%.*]], label [[T2:%.*]], label [[F2:%.*]] ; CHECK: T2: +; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() ; CHECK-NEXT: call void @f3() -; CHECK-NEXT: ret i32 [[B]] +; CHECK-NEXT: ret i32 [[V1]] ; CHECK: F2: -; CHECK-NEXT: ret i32 [[B]] +; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() +; CHECK-NEXT: ret i32 [[V2]] ; br i1 %cond, label %T1, label %F1 @@ -49,25 +40,52 @@ ret i32 %B } +; Negative test +define i32 @test1_undef(i1 %cond) { +; CHECK-LABEL: @test1_undef( +; CHECK-NEXT: T2: +; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() +; CHECK-NEXT: call void @f3() +; CHECK-NEXT: ret i32 [[V1]] +; +T1: + %v1 = call i32 @f1() + br label %Merge + +F1: + %v2 = call i32 @f2() + br label %Merge + +Merge: + %A = phi i1 [true, %T1], [undef, %F1] + %B = phi i32 [%v1, %T1], [%v2, %F1] + %A.fr = freeze i1 %A + br i1 %A.fr, label %T2, label %F2 + +T2: + call void @f3() + ret i32 %B + +F2: + ret i32 %B +} + define i32 @test2(i1 %cond, i1 %cond2) { ; CHECK-LABEL: @test2( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[T1:%.*]], label [[F1:%.*]] -; CHECK: T1: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[MERGE_THREAD:%.*]], label [[MERGE:%.*]] +; CHECK: Merge.thread: ; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() -; CHECK-NEXT: br label [[MERGE:%.*]] -; CHECK: F1: -; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() -; CHECK-NEXT: br label [[MERGE]] +; CHECK-NEXT: br label [[T2:%.*]] ; CHECK: Merge: -; CHECK-NEXT: [[A:%.*]] = phi i1 [ true, [[T1]] ], [ [[COND2:%.*]], [[F1]] ] -; CHECK-NEXT: [[B:%.*]] = phi i32 [ [[V1]], [[T1]] ], [ [[V2]], [[F1]] ] -; CHECK-NEXT: [[A_FR:%.*]] = freeze i1 [[A]] -; CHECK-NEXT: br i1 [[A_FR]], label [[T2:%.*]], label [[F2:%.*]] +; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() +; CHECK-NEXT: [[A_FR:%.*]] = freeze i1 [[COND2:%.*]] +; CHECK-NEXT: br i1 [[A_FR]], label [[T2]], label [[F2:%.*]] ; CHECK: T2: +; CHECK-NEXT: [[B4:%.*]] = phi i32 [ [[V1]], [[MERGE_THREAD]] ], [ [[V2]], [[MERGE]] ] ; CHECK-NEXT: call void @f3() -; CHECK-NEXT: ret i32 [[B]] +; CHECK-NEXT: ret i32 [[B4]] ; CHECK: F2: -; CHECK-NEXT: ret i32 [[B]] +; CHECK-NEXT: ret i32 [[V2]] ; br i1 %cond, label %T1, label %F1