Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -4192,10 +4192,13 @@ Changed = true; } } else { + Value* Cond = BI->getCondition(); if (BI->getSuccessor(0) == BB) { + Builder.CreateAssumption(Builder.CreateNot(Cond)); Builder.CreateBr(BI->getSuccessor(1)); EraseTerminatorAndDCECond(BI); } else if (BI->getSuccessor(1) == BB) { + Builder.CreateAssumption(Cond); Builder.CreateBr(BI->getSuccessor(0)); EraseTerminatorAndDCECond(BI); Changed = true; Index: test/Analysis/ValueTracking/select-pattern.ll =================================================================== --- test/Analysis/ValueTracking/select-pattern.ll +++ test/Analysis/ValueTracking/select-pattern.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -simplifycfg < %s -S | FileCheck %s ; The dead code would cause a select that had itself @@ -7,6 +8,8 @@ define void @PR36045(i1 %t, i32* %b) { ; CHECK-LABEL: @PR36045( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[T:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) ; CHECK-NEXT: ret void ; entry: Index: test/Transforms/CallSiteSplitting/split-loop.ll =================================================================== --- test/Transforms/CallSiteSplitting/split-loop.ll +++ test/Transforms/CallSiteSplitting/split-loop.ll @@ -5,7 +5,9 @@ ; CHECK-LABEL: @test1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 undef, i16 1, i16 0 -; CHECK-NEXT: call void @callee(i16 0) +; CHECK-NEXT: [[TOBOOL18:%.*]] = icmp ne i16 [[SPEC_SELECT]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[TOBOOL18]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) ; CHECK-NEXT: br label [[FOR_COND12:%.*]] ; CHECK: for.cond12: ; CHECK-NEXT: call void @callee(i16 [[SPEC_SELECT]]) @@ -28,12 +30,14 @@ ; CHECK-LABEL: @test2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[S:%.*]] = select i1 undef, i16 1, i16 0 -; CHECK-NEXT: call void @callee(i16 0) +; CHECK-NEXT: [[TOBOOL18:%.*]] = icmp ne i16 [[S]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[TOBOOL18]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) ; CHECK-NEXT: br label [[FOR_COND12:%.*]] ; CHECK: for.cond12: +; CHECK-NEXT: call void @callee(i16 [[S]]) ; CHECK-NEXT: [[ADD:%.*]] = add i16 [[S]], 10 ; CHECK-NEXT: [[ADD2:%.*]] = add i16 [[S]], 10 -; CHECK-NEXT: call void @callee(i16 [[S]]) ; CHECK-NEXT: br label [[FOR_COND12]] ; entry: @@ -55,20 +59,20 @@ ; CHECK-LABEL: @test3( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[S:%.*]] = select i1 undef, i16 1, i16 0 -; CHECK-NEXT: call void @callee(i16 0) +; CHECK-NEXT: [[TOBOOL18:%.*]] = icmp ne i16 [[S]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[TOBOOL18]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) ; CHECK-NEXT: br label [[FOR_COND12:%.*]] ; CHECK: for.cond12: +; CHECK-NEXT: call void @callee(i16 [[S]]) ; CHECK-NEXT: [[ADD:%.*]] = add i16 [[S]], 10 ; CHECK-NEXT: [[ADD2:%.*]] = add i16 [[ADD]], 10 -; CHECK-NEXT: br i1 undef, label [[FOR_COND12_SPLIT:%.*]], label [[EXIT:%.*]] -; CHECK: for.cond12.split: -; CHECK-NEXT: call void @callee(i16 [[S]]) -; CHECK-NEXT: br label [[FOR_COND12]] +; CHECK-NEXT: br i1 undef, label [[FOR_COND12]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret i16 [[ADD2]] ; entry: - %s= select i1 undef, i16 1, i16 0 + %s = select i1 undef, i16 1, i16 0 %tobool18 = icmp ne i16 %s, 0 br i1 %tobool18, label %for.cond12.us, label %for.cond12 @@ -85,6 +89,4 @@ ret i16 %add2 } -define internal void @callee(i16 %flag) { - ret void -} +declare void @callee(i16 %flag) Index: test/Transforms/SimplifyCFG/UnreachableEliminate.ll =================================================================== --- test/Transforms/SimplifyCFG/UnreachableEliminate.ll +++ test/Transforms/SimplifyCFG/UnreachableEliminate.ll @@ -1,53 +1,59 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -S | FileCheck %s define void @test1(i1 %C, i1* %BP) { ; CHECK-LABEL: @test1( -; CHECK: entry: -; CHECK-NEXT: ret void +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: ret void +; entry: - br i1 %C, label %T, label %F + br i1 %C, label %T, label %F T: - store i1 %C, i1* %BP - unreachable + store i1 %C, i1* %BP + unreachable F: - ret void + ret void } define void @test2() personality i32 (...)* @__gxx_personality_v0 { ; CHECK-LABEL: @test2( -; CHECK: entry: -; CHECK-NEXT: call void @test2() -; CHECK-NEXT: ret void +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @test2() +; CHECK-NEXT: ret void +; entry: - invoke void @test2( ) - to label %N unwind label %U + invoke void @test2( ) + to label %N unwind label %U U: %res = landingpad { i8* } - cleanup - unreachable + cleanup + unreachable N: - ret void + ret void } declare i32 @__gxx_personality_v0(...) define i32 @test3(i32 %v) { ; CHECK-LABEL: @test3( -; CHECK: entry: -; CHECK-NEXT: [[CMP:%[A-Za-z0-9]+]] = icmp eq i32 %v, 2 -; CHECK-NEXT: select i1 [[CMP]], i32 2, i32 1 -; CHECK-NEXT: ret -entry: - switch i32 %v, label %default [ - i32 1, label %U - i32 2, label %T - ] +; CHECK-NEXT: entry: +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[V:%.*]], 2 +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND]], i32 2, i32 1 +; CHECK-NEXT: ret i32 [[SPEC_SELECT]] +; +entry: + switch i32 %v, label %default [ + i32 1, label %U + i32 2, label %T + ] default: - ret i32 1 + ret i32 1 U: - unreachable + unreachable T: - ret i32 2 + ret i32 2 } @@ -56,21 +62,22 @@ ;; the latter. define void @test5(i1 %cond, i8* %ptr) { - -; CHECK-LABEL: test5 -; CHECK: entry: -; CHECK-NOT: select -; CHECK: store i8 2, i8* %ptr -; CHECK: ret +; CHECK-LABEL: @test5( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: store i8 2, i8* [[PTR:%.*]], align 8 +; CHECK-NEXT: ret void +; entry: br i1 %cond, label %bb1, label %bb3 bb3: - br label %bb2 + br label %bb2 bb1: - br label %bb2 + br label %bb2 bb2: %ptr.2 = phi i8* [ %ptr, %bb3 ], [ null, %bb1 ] @@ -79,34 +86,35 @@ } define void @test5_no_null_opt(i1 %cond, i8* %ptr) #0 { - -; CHECK-LABEL: test5_no_null_opt -; CHECK: entry: -; CHECK: %[[SEL:.*]] = select i1 %cond, i8* null, i8* %ptr -; CHECK: store i8 2, i8* %[[SEL]] +; CHECK-LABEL: @test5_no_null_opt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DOTPTR:%.*]] = select i1 [[COND:%.*]], i8* null, i8* [[PTR:%.*]] +; CHECK-NEXT: store i8 2, i8* [[DOTPTR]], align 8 +; CHECK-NEXT: ret void +; entry: br i1 %cond, label %bb1, label %bb3 bb3: - br label %bb2 + br label %bb2 bb1: - br label %bb2 + br label %bb2 bb2: %ptr.2 = phi i8* [ %ptr, %bb3 ], [ null, %bb1 ] store i8 2, i8* %ptr.2, align 8 ret void } - -; CHECK-LABEL: test6 -; CHECK: entry: -; CHECK-NOT: select -; CHECK: store i8 2, i8* %ptr -; CHECK: ret - define void @test6(i1 %cond, i8* %ptr) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: store i8 2, i8* [[PTR:%.*]], align 8 +; CHECK-NEXT: ret void +; entry: br i1 %cond, label %bb1, label %bb2 @@ -119,12 +127,13 @@ ret void } -; CHECK-LABEL: test6_no_null_opt -; CHECK: entry: -; CHECK: %[[SEL:.*]] = select i1 %cond, i8* null, i8* %ptr -; CHECK: store i8 2, i8* %[[SEL]] - define void @test6_no_null_opt(i1 %cond, i8* %ptr) #0 { +; CHECK-LABEL: @test6_no_null_opt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND:%.*]], i8* null, i8* [[PTR:%.*]] +; CHECK-NEXT: store i8 2, i8* [[SPEC_SELECT]], align 8 +; CHECK-NEXT: ret void +; entry: br i1 %cond, label %bb1, label %bb2 @@ -139,6 +148,12 @@ define i32 @test7(i1 %X) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: ret i32 0 +; entry: br i1 %X, label %if, label %else @@ -150,11 +165,15 @@ %phi = phi i32 [ 0, %entry ], [ 1, %if ] ret i32 %phi } -; CHECK-LABEL: define i32 @test7( -; CHECK-NOT: call -; CHECK: ret i32 0 define void @test8(i1 %X, void ()* %Y) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: call void [[Y:%.*]]() +; CHECK-NEXT: ret void +; entry: br i1 %X, label %if, label %else @@ -166,10 +185,14 @@ call void %phi() ret void } -; CHECK-LABEL: define void @test8( -; CHECK: call void %Y( define void @test8_no_null_opt(i1 %X, void ()* %Y) #0 { +; CHECK-LABEL: @test8_no_null_opt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], void ()* null, void ()* [[Y:%.*]] +; CHECK-NEXT: call void [[SPEC_SELECT]]() +; CHECK-NEXT: ret void +; entry: br i1 %X, label %if, label %else @@ -181,8 +204,5 @@ call void %phi() ret void } -attributes #0 = { "null-pointer-is-valid"="true" } -; CHECK-LABEL: define void @test8_no_null_opt( -; CHECK: %[[SEL:.*]] = select i1 %X, void ()* null, void ()* %Y -; CHECK: call void %[[SEL]] +attributes #0 = { "null-pointer-is-valid"="true" } Index: test/Transforms/SimplifyCFG/unreachable_assume.ll =================================================================== --- test/Transforms/SimplifyCFG/unreachable_assume.ll +++ test/Transforms/SimplifyCFG/unreachable_assume.ll @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -simplifycfg -instcombine -S | FileCheck %s +define i32 @assume1(i32 %p) { +; CHECK-LABEL: @assume1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[P:%.*]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: ret i32 [[P]] +; +entry: + %cmp = icmp sle i32 %p, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: + unreachable + +if.end: + %call = call i32 @abs(i32 %p) + ret i32 %call +} + + +define i32 @assume2(i32 %p) { +; CHECK-LABEL: @assume2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[P:%.*]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: ret i32 [[P]] +; +entry: + %cmp = icmp sgt i32 %p, 0 + br i1 %cmp, label %if.then, label %if.else + +if.then: + br label %if.end + +if.else: + unreachable + +if.end: + %call = call i32 @abs(i32 %p) + ret i32 %call +} + +declare i32 @abs(i32)