Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -5557,7 +5557,7 @@ // be BitWidth) unsigned Shift = 64; for (auto &V : Values) - Shift = std::min(Shift, countTrailingZeros((uint64_t)V); + Shift = std::min(Shift, countTrailingZeros((uint64_t)V)); if (Shift > 0) for (auto &V : Values) V = (int64_t)((uint64_t)V >> Shift); @@ -5578,18 +5578,22 @@ auto *Ty = cast(SI->getCondition()->getType()); Builder.SetInsertPoint(SI); - auto *ShiftC = ConstantInt::get(Ty, Shift); - auto *Sub = Builder.CreateSub(SI->getCondition(), ConstantInt::get(Ty, Base)); - auto *LShr = Builder.CreateLShr(Sub, ShiftC); - auto *Shl = Builder.CreateShl(Sub, Ty->getBitWidth() - Shift); - auto *Rot = Builder.CreateOr(LShr, Shl); - SI->replaceUsesOfWith(SI->getCondition(), Rot); + Value *Key = SI->getCondition(); + if (Base > 0) { + Key = Builder.CreateSub(Key, ConstantInt::get(Ty, Base), "switch.rangereduce"); + } + if (Shift > 0) { + auto *ShiftC = ConstantInt::get(Ty, Shift); + Function *Fshr = Intrinsic::getDeclaration(SI->getModule(), Intrinsic::fshr, Ty); + Key = Builder.CreateCall(Fshr, {Key, Key, ShiftC}, "switch.rangereduce"); + } + SI->replaceUsesOfWith(SI->getCondition(), Key); for (auto Case : SI->cases()) { auto *Orig = Case.getCaseValue(); auto Sub = Orig->getValue() - APInt(Ty->getBitWidth(), Base); Case.setValue( - cast(ConstantInt::get(Ty, Sub.lshr(ShiftC->getValue())))); + cast(ConstantInt::get(Ty, Sub.lshr(Shift)))); } return true; } Index: test/Transforms/SimplifyCFG/rangereduce.ll =================================================================== --- test/Transforms/SimplifyCFG/rangereduce.ll +++ test/Transforms/SimplifyCFG/rangereduce.ll @@ -6,11 +6,9 @@ define i32 @test1(i32 %a) { ; CHECK-LABEL: @test1( -; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 97 -; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 2 -; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 30 -; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] -; CHECK-NEXT: switch i32 [[TMP4]], label [[DEF:%.*]] [ +; CHECK-NEXT: [[SWITCH_RANGEREDUCE:%.*]] = sub i32 [[A:%.*]], 97 +; CHECK-NEXT: [[SWITCH_RANGEREDUCE1:%.*]] = call i32 @llvm.fshr.i32(i32 [[SWITCH_RANGEREDUCE]], i32 [[SWITCH_RANGEREDUCE]], i32 2) +; CHECK-NEXT: switch i32 [[SWITCH_RANGEREDUCE1]], label [[DEF:%.*]] [ ; CHECK-NEXT: i32 0, label [[ONE:%.*]] ; CHECK-NEXT: i32 1, label [[TWO:%.*]] ; CHECK-NEXT: i32 2, label [[THREE:%.*]] @@ -192,11 +190,8 @@ define i32 @test6(i32 %a) optsize { ; CHECK-LABEL: @test6( -; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], -109 -; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 2 -; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 30 -; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] -; CHECK-NEXT: switch i32 [[TMP4]], label [[DEF:%.*]] [ +; CHECK-NEXT: [[SWITCH_RANGEREDUCE:%.*]] = call i32 @llvm.fshr.i32(i32 [[A:%.*]], i32 [[A]], i32 2) +; CHECK-NEXT: switch i32 [[SWITCH_RANGEREDUCE]], label [[DEF:%.*]] [ ; CHECK-NEXT: i32 3, label [[ONE:%.*]] ; CHECK-NEXT: i32 2, label [[TWO:%.*]] ; CHECK-NEXT: i32 1, label [[THREE:%.*]] @@ -232,14 +227,11 @@ define i8 @test7(i8 %a) optsize { ; CHECK-LABEL: @test7( -; CHECK-NEXT: [[TMP1:%.*]] = sub i8 [[A:%.*]], -36 -; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], 2 -; CHECK-NEXT: [[TMP3:%.*]] = shl i8 [[TMP1]], 6 -; CHECK-NEXT: [[TMP4:%.*]] = or i8 [[TMP2]], [[TMP3]] -; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i8 [[TMP4]], 4 -; CHECK-NEXT: br i1 [[TMP5]], label [[SWITCH_LOOKUP:%.*]], label [[DEF:%.*]] +; CHECK-NEXT: [[SWITCH_RANGEREDUCE:%.*]] = call i8 @llvm.fshr.i8(i8 [[A:%.*]], i8 [[A]], i8 2) +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[SWITCH_RANGEREDUCE]], 4 +; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[DEF:%.*]] ; CHECK: switch.lookup: -; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i8 [[TMP4]] to i32 +; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i8 [[SWITCH_RANGEREDUCE]] to i32 ; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul i32 [[SWITCH_CAST]], 8 ; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i32 -943228976, [[SWITCH_SHIFTAMT]] ; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i32 [[SWITCH_DOWNSHIFT]] to i8 @@ -267,11 +259,9 @@ define i32 @test8(i32 %a) optsize { ; CHECK-LABEL: @test8( -; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 97 -; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 2 -; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 30 -; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] -; CHECK-NEXT: switch i32 [[TMP4]], label [[DEF:%.*]] [ +; CHECK-NEXT: [[SWITCH_RANGEREDUCE:%.*]] = sub i32 [[A:%.*]], 97 +; CHECK-NEXT: [[SWITCH_RANGEREDUCE1:%.*]] = call i32 @llvm.fshr.i32(i32 [[SWITCH_RANGEREDUCE]], i32 [[SWITCH_RANGEREDUCE]], i32 2) +; CHECK-NEXT: switch i32 [[SWITCH_RANGEREDUCE1]], label [[DEF:%.*]] [ ; CHECK-NEXT: i32 0, label [[ONE:%.*]] ; CHECK-NEXT: i32 1, label [[TWO:%.*]] ; CHECK-NEXT: i32 2, label [[THREE:%.*]] @@ -307,11 +297,9 @@ define i32 @test9(i32 %a) { ; CHECK-LABEL: @test9( -; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 6 -; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 1 -; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 31 -; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] -; CHECK-NEXT: switch i32 [[TMP4]], label [[DEF:%.*]] [ +; CHECK-NEXT: [[SWITCH_RANGEREDUCE:%.*]] = sub i32 [[A:%.*]], 6 +; CHECK-NEXT: [[SWITCH_RANGEREDUCE1:%.*]] = call i32 @llvm.fshr.i32(i32 [[SWITCH_RANGEREDUCE]], i32 [[SWITCH_RANGEREDUCE]], i32 1) +; CHECK-NEXT: switch i32 [[SWITCH_RANGEREDUCE1]], label [[DEF:%.*]] [ ; CHECK-NEXT: i32 6, label [[ONE:%.*]] ; CHECK-NEXT: i32 7, label [[TWO:%.*]] ; CHECK-NEXT: i32 0, label [[THREE:%.*]] Index: test/Transforms/SimplifyCFG/switch-dead-default.ll =================================================================== --- test/Transforms/SimplifyCFG/switch-dead-default.ll +++ test/Transforms/SimplifyCFG/switch-dead-default.ll @@ -5,12 +5,14 @@ define void @test(i1 %a) { ; CHECK-LABEL: @test( -; CHECK-NEXT: br i1 [[A:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] +; CHECK-NEXT: [[A_OFF:%.*]] = add i1 [[A:%.*]], true +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i1 [[A_OFF]], true +; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 1) ; CHECK-NEXT: ret void ; CHECK: false: -; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: call void @foo(i32 3) ; CHECK-NEXT: ret void ; switch i1 %a, label %default [i1 1, label %true @@ -35,16 +37,16 @@ ; CHECK-NEXT: i2 -1, label [[CASE3:%.*]] ; CHECK-NEXT: ] ; CHECK: case0: -; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: call void @foo(i32 0) ; CHECK-NEXT: ret void ; CHECK: case1: -; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 1) ; CHECK-NEXT: ret void ; CHECK: case2: -; CHECK-NEXT: tail call void @foo(i32 2) +; CHECK-NEXT: call void @foo(i32 2) ; CHECK-NEXT: ret void ; CHECK: case3: -; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: call void @foo(i32 3) ; CHECK-NEXT: ret void ; CHECK: default1: ; CHECK-NEXT: unreachable @@ -80,16 +82,16 @@ ; CHECK-NEXT: i2 -2, label [[CASE2:%.*]] ; CHECK-NEXT: ] ; CHECK: case0: -; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: call void @foo(i32 0) ; CHECK-NEXT: ret void ; CHECK: case1: -; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 1) ; CHECK-NEXT: ret void ; CHECK: case2: -; CHECK-NEXT: tail call void @foo(i32 2) +; CHECK-NEXT: call void @foo(i32 2) ; CHECK-NEXT: ret void ; CHECK: default: -; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: call void @foo(i32 0) ; CHECK-NEXT: ret void ; switch i2 %a, label %default [i2 0, label %case0 @@ -119,13 +121,13 @@ ; CHECK-NEXT: i128 1, label [[CASE1:%.*]] ; CHECK-NEXT: ] ; CHECK: case0: -; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: call void @foo(i32 0) ; CHECK-NEXT: ret void ; CHECK: case1: -; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 1) ; CHECK-NEXT: ret void ; CHECK: default: -; CHECK-NEXT: tail call void @foo(i32 0) +; CHECK-NEXT: call void @foo(i32 0) ; CHECK-NEXT: ret void ; switch i128 %a, label %default [i128 0, label %case0 @@ -146,14 +148,15 @@ define void @test5(i8 %a) { ; CHECK-LABEL: @test5( ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[A:%.*]], 2 -; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], 1 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[A_OFF:%.*]] = add i8 [[A]], -1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[A_OFF]], 1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 1) ; CHECK-NEXT: ret void ; CHECK: false: -; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: call void @foo(i32 3) ; CHECK-NEXT: ret void ; %cmp = icmp ult i8 %a, 2 @@ -174,15 +177,17 @@ ;; All but one bit known one define void @test6(i8 %a) { ; CHECK-LABEL: @test6( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[A:%.*]], -3 -; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i8 [[A:%.*]], -2 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], -2 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[A_OFF:%.*]] = add i8 [[A]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[A_OFF]], 1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 1) ; CHECK-NEXT: ret void ; CHECK: false: -; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: call void @foo(i32 3) ; CHECK-NEXT: ret void ; %and = and i8 %a, 254 @@ -205,15 +210,17 @@ ; within a single run of simplify-cfg define void @test7(i8 %a) { ; CHECK-LABEL: @test7( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[A:%.*]], -3 -; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i8 [[A:%.*]], -2 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], -2 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[A_OFF:%.*]] = add i8 [[A]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[A_OFF]], 1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: -; CHECK-NEXT: tail call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 1) ; CHECK-NEXT: ret void ; CHECK: false: -; CHECK-NEXT: tail call void @foo(i32 3) +; CHECK-NEXT: call void @foo(i32 3) ; CHECK-NEXT: ret void ; %and = and i8 %a, 254 @@ -243,7 +250,22 @@ ;; but it doesn't hurt to confirm. define void @test8(i8 %a) { ; CHECK-LABEL: @test8( -; CHECK-NEXT: unreachable +; CHECK-NEXT: [[AND:%.*]] = and i8 [[A:%.*]], -2 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], undef +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: switch i8 [[A]], label [[DEFAULT:%.*]] [ +; CHECK-NEXT: i8 -1, label [[TRUE:%.*]] +; CHECK-NEXT: i8 -2, label [[FALSE:%.*]] +; CHECK-NEXT: ] +; CHECK: true: +; CHECK-NEXT: call void @foo(i32 1) +; CHECK-NEXT: ret void +; CHECK: false: +; CHECK-NEXT: call void @foo(i32 3) +; CHECK-NEXT: ret void +; CHECK: default: +; CHECK-NEXT: call void @foo(i32 2) +; CHECK-NEXT: ret void ; %and = and i8 %a, 254 %cmp = icmp eq i8 %and, undef