for (SwitchInst::CaseIt E = SI->case_end(); CI != E; ++CI) {
ConstantInt *CaseVal = CI->getCaseValue();
- if (CaseVal->getValue().slt(MinCaseVal->getValue()))
+ if (CaseVal->getValue().ult(MinCaseVal->getValue()))
MinCaseVal = CaseVal;
- if (CaseVal->getValue().sgt(MaxCaseVal->getValue()))
+ if (CaseVal->getValue().ugt(MaxCaseVal->getValue()))
MaxCaseVal = CaseVal;
// Resulting value at phi nodes for this case value.
}
uint64_t NumResults = ResultLists[PHIs[0]].size();
- APInt RangeSpread = MaxCaseVal->getValue() - MinCaseVal->getValue();
- uint64_t TableSize = RangeSpread.getLimitedValue() + 1;
+ uint64_t TableSize = MaxCaseVal->getValue().getLimitedValue() + 1;
bool TableHasHoles = (NumResults < TableSize);
// If the table has holes, we need a constant result for the default case
// Compute the table index value.
Builder.SetInsertPoint(SI);
- Value *TableIndex;
- if (MinCaseVal->isNullValue())
- TableIndex = SI->getCondition();
- else
- TableIndex =
- Builder.CreateSub(SI->getCondition(), MinCaseVal, "switch.tableidx");
+ Value *TableIndex = SI->getCondition();
// Compute the maximum table size representable by the integer type we are
// switching upon.
LookupBB = BasicBlock::Create(Mod.getContext(), "switch.lookup",
CommonDest->getParent(), CommonDest);
+ // When doing the register-sized hole-check, unconditionally use a
+ // subtraction.
+ TableIndex = Builder.CreateSub(TableIndex, MinCaseVal);
+
// Make the mask's bitwidth at least 8-bit and a power-of-2 to avoid
// unnecessary illegal types.
uint64_t TableSizePowOf2 = NextPowerOf2(std::max(7ULL, TableSize - 1ULL));
// If using a bitmask, use any value to fill the lookup table holes.
Constant *DV = NeedMask ? ResultLists[PHI][0].second : DefaultResults[PHI];
StringRef FuncName = Fn->getName();
- SwitchLookupTable Table(Mod, TableSize, MinCaseVal, ResultList, DV, DL,
- FuncName);
+ // Base is 0 unless using a hole check
+ ConstantInt *Base =
+ NeedMask ? MinCaseVal
+ : ConstantInt::get(Mod.getContext(), APInt(CaseSize, 0));
+ SwitchLookupTable Table(Mod, TableSize, Base, ResultList, DV, DL, FuncName);
Value *Result = Table.BuildLookup(TableIndex, Builder);
return true;
}
-static bool isSwitchDense(ArrayRef<int64_t> Values) {
- // See also SelectionDAGBuilder::isDense(), which this function was based on.
- uint64_t Diff = (uint64_t)Values.back() - (uint64_t)Values.front();
- uint64_t Range = Diff + 1;
- uint64_t NumCases = Values.size();
- // 40% is the default density for building a jump table in optsize/minsize
- // mode.
- uint64_t MinDensity = 40;
-
- return NumCases * 100 >= Range * MinDensity;
-}
-
/// Try to transform a switch that has "holes" in it to a contiguous sequence
/// of cases.
///
static bool ReduceSwitchRange(SwitchInst *SI, IRBuilder<> &Builder,
const DataLayout &DL,
const TargetTransformInfo &TTI) {
+ // The number of cases that need to be removed by a subtraction operation
+ // to make it worth using.
+ const unsigned SubThreshold = (SI->getFunction()->hasOptSize() ? 2 : 8);
auto *CondTy = cast<IntegerType>(SI->getCondition()->getType());
- if (CondTy->getIntegerBitWidth() > 64 ||
- !DL.fitsInLegalInteger(CondTy->getIntegerBitWidth()))
+ unsigned BitWidth = CondTy->getIntegerBitWidth();
+ if (BitWidth > 64 || !DL.fitsInLegalInteger(BitWidth))
return false;
// Only bother with this optimization if there are more than 3 switch cases;
// SDAG will only bother creating jump tables for 4 or more cases.
+ // This is also useful when using the LowerSwitch transform, but not with
+ // so few cases.
if (SI->getNumCases() < 4)
return false;
- // This transform is agnostic to the signedness of the input or case values.
- // We can treat the case values as signed or unsigned. We can optimize more
- // common cases such as a sequence crossing zero {-4,0,4,8} if we interpret
- // case values as signed.
- SmallVector<int64_t, 4> Values;
+ // We organize the range to start from 0, if it is not already close.
+ SmallVector<uint64_t, 4> Values;
for (auto &C : SI->cases())
- Values.push_back(C.getCaseValue()->getValue().getSExtValue());
+ Values.push_back(C.getCaseValue()->getValue().getLimitedValue());
llvm::sort(Values);
- // If the switch is already dense, there's nothing useful to do here.
- if (isSwitchDense(Values))
- return false;
-
- // First, transform the values such that they start at zero and ascend.
- int64_t Base = Values[0];
- for (auto &V : Values)
- V -= (uint64_t)(Base);
+ bool MadeChanges = false;
+ // We must first look find the best start point, for example if we have a
+ // series that crosses zero: -2, -1, 0, 1, 2.
+ uint64_t BestDistance =
+ APInt::getMaxValue(CondTy->getIntegerBitWidth()).getLimitedValue() -
+ Values.back() + Values.front() + 1;
+ unsigned BestIndex = 0;
+ for (unsigned I = 1, E = Values.size(); I != E; I++) {
+ if (Values[I] - Values[I - 1] > BestDistance) {
+ BestIndex = I;
+ BestDistance = Values[I] - Values[I - 1];
+ }
+ }
+ uint64_t Base = 0;
+ // Now transform the values such that they start at zero and ascend.
+ if (Values[BestIndex] >= SubThreshold) {
+ Base = Values[BestIndex];
+ MadeChanges = true;
+ for (auto &V : Values)
+ V = (APInt(BitWidth, V) - Base).getLimitedValue();
+ }
// Now we have signed numbers that have been shifted so that, given enough
// precision, there are no negative values. Since the rest of the transform
// less than 64.
unsigned Shift = 64;
for (auto &V : Values)
- Shift = std::min(Shift, countTrailingZeros((uint64_t)V);
+ Shift = std::min(Shift, countTrailingZeros(V));
assert(Shift < 64);
- if (Shift > 0)
+ if (Shift > 0) {
+ MadeChanges = true;
for (auto &V : Values)
- V = (int64_t)((uint64_t)V >> Shift);
+ V >>= Shift;
+ }
- if (!isSwitchDense(Values))
- // Transform didn't create a dense switch.
+ if (!MadeChanges)
+ // We didn't do anything.
return false;
// The obvious transform is to shift the switch condition right and emit a
auto *Ty = cast<IntegerType>(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));
+ if (Shift > 0) {
+ // FIXME replace with fshr?
+ auto *ShiftC = ConstantInt::get(Ty, Shift);
+ auto *LShr = Builder.CreateLShr(Key, ShiftC);
+ auto *Shl = Builder.CreateShl(Key, Ty->getBitWidth() - Shift);
+ Key = Builder.CreateOr(LShr, Shl);
+ }
+ 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>(ConstantInt::get(Ty, Sub.lshr(ShiftC->getValue()))));
+ Case.setValue(cast<ConstantInt>(ConstantInt::get(Ty, Sub.lshr(Shift))));
}
return true;
}
if (Options.ForwardSwitchCondToPhi && ForwardSwitchConditionToPHI(SI))
return requestResimplify();
+ if (ReduceSwitchRange(SI, Builder, DL, TTI))
+ return requestResimplify();
+
// The conversion from switch to lookup tables results in difficult-to-analyze
// code and makes pruning branches much harder. This is a problem if the
// switch expression itself can still be restricted as a result of inlining or
SwitchToLookupTable(SI, Builder, DL, TTI))
return requestResimplify();
- if (ReduceSwitchRange(SI, Builder, DL, TTI))
- return requestResimplify();
-
return false;
}
; RUN: opt < %s -simplifycfg -switch-to-lookup -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
; RUN: opt < %s -passes='simplify-cfg<switch-to-lookup>' -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; In the presence of "-no-jump-tables"="true", simplifycfg should not convert switches to lookup tables.
; CHECK: @switch.table.bar = private unnamed_addr constant [4 x i32] [i32 55, i32 123, i32 0, i32 -1]
define i32 @foo(i32 %c) "no-jump-tables"="true" {
; CHECK-LABEL: @foo(
; CHECK-NEXT: entry:
-; CHECK-NEXT: switch i32 [[C:%.*]], label [[SW_DEFAULT:%.*]] [
-; CHECK-NEXT: i32 42, label [[RETURN:%.*]]
-; CHECK-NEXT: i32 43, label [[SW_BB1:%.*]]
-; CHECK-NEXT: i32 44, label [[SW_BB2:%.*]]
-; CHECK-NEXT: i32 45, label [[SW_BB3:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], 42
+; CHECK-NEXT: switch i32 [[TMP0]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i32 0, label [[RETURN:%.*]]
+; CHECK-NEXT: i32 1, label [[SW_BB1:%.*]]
+; CHECK-NEXT: i32 2, label [[SW_BB2:%.*]]
+; CHECK-NEXT: i32 3, label [[SW_BB3:%.*]]
; CHECK-NEXT: ]
; CHECK: sw.bb1:
; CHECK-NEXT: br label [[RETURN]]
define i32 @bar(i32 %c) {
; CHECK-LABEL: @bar(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], 42
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 4
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], 42
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 4
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @switch.table.bar, i32 0, i32 [[SWITCH_TABLEIDX]]
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @switch.table.bar, i32 0, i32 [[TMP0]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
; CHECK: return:
define i64 @test(i3 %arg) {
; CHECK-LABEL: @test(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i3 [[ARG:%.*]], -4
-; CHECK-NEXT: [[SWITCH_TABLEIDX_ZEXT:%.*]] = zext i3 [[SWITCH_TABLEIDX]] to i4
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [8 x i64], [8 x i64]* @switch.table.test, i32 0, i4 [[SWITCH_TABLEIDX_ZEXT]]
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i3 [[ARG:%.*]], -1
+; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[DEFAULT:%.*]]
+; CHECK: switch.lookup:
+; CHECK-NEXT: [[SWITCH_TABLEIDX_ZEXT:%.*]] = zext i3 [[ARG]] to i4
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i64], [7 x i64]* @switch.table.test, i32 0, i4 [[SWITCH_TABLEIDX_ZEXT]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i64, i64* [[SWITCH_GEP]]
-; CHECK-NEXT: [[V3:%.*]] = add i64 [[SWITCH_LOAD]], 0
+; CHECK-NEXT: br label [[DEFAULT]]
+; CHECK: Default:
+; CHECK-NEXT: [[V1:%.*]] = phi i64 [ 8, [[ENTRY:%.*]] ], [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ]
+; CHECK-NEXT: [[V3:%.*]] = add i64 [[V1]], 0
; CHECK-NEXT: ret i64 [[V3]]
;
entry:
define i64 @_TFO6reduce1E5toRawfS0_FT_Si(i2) {
; CHECK-LABEL: @_TFO6reduce1E5toRawfS0_FT_Si(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i2 [[TMP0:%.*]], -2
-; CHECK-NEXT: [[SWITCH_TABLEIDX_ZEXT:%.*]] = zext i2 [[SWITCH_TABLEIDX]] to i3
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i64], [4 x i64]* @switch.table._TFO6reduce1E5toRawfS0_FT_Si, i32 0, i3 [[SWITCH_TABLEIDX_ZEXT]]
-; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i64, i64* [[SWITCH_GEP]]
-; CHECK-NEXT: ret i64 [[SWITCH_LOAD]]
+; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i2 [[TMP0:%.*]] to i64
+; CHECK-NEXT: ret i64 [[SWITCH_IDX_CAST]]
;
entry:
switch i2 %0, label %1 [
define i32 @f(i32 %c) {
; CHECK-LABEL: @f(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], 42
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 7
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], 42
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 7
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], [7 x i32]* @switch.table.f, i32 0, i32 [[SWITCH_TABLEIDX]]
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], [7 x i32]* @switch.table.f, i32 0, i32 [[TMP0]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
; CHECK: return:
define i8 @char(i32 %c) {
; CHECK-LABEL: @char(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], 42
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 9
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], 42
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 9
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [9 x i8], [9 x i8]* @switch.table.char, i32 0, i32 [[SWITCH_TABLEIDX]]
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [9 x i8], [9 x i8]* @switch.table.char, i32 0, i32 [[TMP0]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i8, i8* [[SWITCH_GEP]]
; CHECK-NEXT: ret i8 [[SWITCH_LOAD]]
; CHECK: return:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[C:%.*]], 33
; CHECK-NEXT: br i1 [[CMP]], label [[LOR_END:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
; CHECK: switch.early.test:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i8 [[C]], 34
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i8 [[SWITCH_TABLEIDX]], 59
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[LOR_END]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[C]], 34
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[TMP0]], 59
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[LOR_END]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i8 [[SWITCH_TABLEIDX]] to i59
+; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i8 [[TMP0]] to i59
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul i59 [[SWITCH_CAST]], 1
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i59 -288230375765830623, [[SWITCH_SHIFTAMT]]
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i59 [[SWITCH_DOWNSHIFT]] to i1
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
-; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ [[SWITCH_MASKED]], [[SWITCH_LOOKUP]] ], [ false, [[SWITCH_EARLY_TEST]] ]
-; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT: [[TMP2:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ [[SWITCH_MASKED]], [[SWITCH_LOOKUP]] ], [ false, [[SWITCH_EARLY_TEST]] ]
+; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP2]] to i32
; CHECK-NEXT: ret i32 [[LOR_EXT]]
;
entry:
define i32 @overflow(i32 %type) {
; CHECK-LABEL: @overflow(
; CHECK-NEXT: entry:
-; CHECK-NEXT: switch i32 [[TYPE:%.*]], label [[IF_END:%.*]] [
-; CHECK-NEXT: i32 3, label [[SW_BB3:%.*]]
-; CHECK-NEXT: i32 -2147483645, label [[SW_BB3]]
-; CHECK-NEXT: i32 1, label [[SW_BB1:%.*]]
-; CHECK-NEXT: i32 2, label [[SW_BB2:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[TYPE:%.*]], -2147483645
+; CHECK-NEXT: switch i32 [[TMP0]], label [[IF_END:%.*]] [
+; CHECK-NEXT: i32 -2147483648, label [[SW_BB3:%.*]]
+; CHECK-NEXT: i32 0, label [[SW_BB3]]
+; CHECK-NEXT: i32 2147483646, label [[SW_BB1:%.*]]
+; CHECK-NEXT: i32 2147483647, label [[SW_BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: sw.bb1:
; CHECK-NEXT: br label [[IF_END]]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X]], -10
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[CMP]], i32 [[MUL]], i32 [[X]]
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[SPEC_SELECT]], 1
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 199
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SPEC_SELECT]], 200
; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [199 x i32], [199 x i32]* @switch.table.large, i32 0, i32 [[SWITCH_TABLEIDX]]
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [200 x i32], [200 x i32]* @switch.table.large, i32 0, i32 [[SPEC_SELECT]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
; CHECK: return:
define i32 @cprop(i32 %x, i32 %y) {
; CHECK-LABEL: @cprop(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[X:%.*]], 1
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 7
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[X:%.*]], 8
; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], [7 x i32]* @switch.table.cprop, i32 0, i32 [[SWITCH_TABLEIDX]]
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [8 x i32], [8 x i32]* @switch.table.cprop, i32 0, i32 [[X]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
; CHECK: return:
define i96 @illegaltype(i32 %c) {
; CHECK-LABEL: @illegaltype(
; CHECK-NEXT: entry:
-; CHECK-NEXT: switch i32 [[C:%.*]], label [[SW_DEFAULT:%.*]] [
-; CHECK-NEXT: i32 42, label [[RETURN:%.*]]
-; CHECK-NEXT: i32 43, label [[SW_BB1:%.*]]
-; CHECK-NEXT: i32 44, label [[SW_BB2:%.*]]
-; CHECK-NEXT: i32 45, label [[SW_BB3:%.*]]
-; CHECK-NEXT: i32 46, label [[SW_BB4:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], 42
+; CHECK-NEXT: switch i32 [[TMP0]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i32 0, label [[RETURN:%.*]]
+; CHECK-NEXT: i32 1, label [[SW_BB1:%.*]]
+; CHECK-NEXT: i32 2, label [[SW_BB2:%.*]]
+; CHECK-NEXT: i32 3, label [[SW_BB3:%.*]]
+; CHECK-NEXT: i32 4, label [[SW_BB4:%.*]]
; CHECK-NEXT: ]
; CHECK: sw.bb1:
; CHECK-NEXT: br label [[RETURN]]
; CHECK-NEXT: call void @exit(i32 1)
; CHECK-NEXT: unreachable
; CHECK: switch.hole_check:
-; CHECK-NEXT: [[SWITCH_MASKINDEX:%.*]] = trunc i32 [[C]] to i8
+; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[C]], 0
+; CHECK-NEXT: [[SWITCH_MASKINDEX:%.*]] = trunc i32 [[TMP1]] to i8
; CHECK-NEXT: [[SWITCH_SHIFTED:%.*]] = lshr i8 47, [[SWITCH_MASKINDEX]]
; CHECK-NEXT: [[SWITCH_LOBIT:%.*]] = trunc i8 [[SWITCH_SHIFTED]] to i1
; CHECK-NEXT: br i1 [[SWITCH_LOBIT]], label [[SWITCH_LOOKUP:%.*]], label [[SW_DEFAULT]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @switch.table.nodefaultwithholes, i32 0, i32 [[C]]
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @switch.table.nodefaultwithholes, i32 0, i32 [[TMP1]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
;
define i8 @linearmap1(i32 %c) {
; CHECK-LABEL: @linearmap1(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], 10
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 4
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 4
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[SWITCH_TABLEIDX]] to i8
+; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[TMP0]] to i8
; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul i8 [[SWITCH_IDX_CAST]], -5
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i8 [[SWITCH_IDX_MULT]], 18
; CHECK-NEXT: ret i8 [[SWITCH_OFFSET]]
define i32 @linearmap2(i8 %c) {
; CHECK-LABEL: @linearmap2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i8 [[C:%.*]], -13
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i8 [[SWITCH_TABLEIDX]], 4
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[C:%.*]], -13
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[TMP0]], 4
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i8 [[SWITCH_TABLEIDX]] to i32
+; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i8 [[TMP0]] to i32
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[SWITCH_IDX_CAST]], 18
; CHECK-NEXT: ret i32 [[SWITCH_OFFSET]]
; CHECK: return:
define i8 @linearmap3(i32 %c) {
; CHECK-LABEL: @linearmap3(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], 10
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 4
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 4
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[SWITCH_TABLEIDX]] to i8
+; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[TMP0]] to i8
; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul i8 [[SWITCH_IDX_CAST]], 100
; CHECK-NEXT: ret i8 [[SWITCH_IDX_MULT]]
; CHECK: return:
define i8 @linearmap4(i32 %c) {
; CHECK-LABEL: @linearmap4(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], -2
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 4
-; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[C:%.*]], -2
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 4
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[SWITCH_TABLEIDX]] to i8
+; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[TMP0]] to i8
; CHECK-NEXT: ret i8 [[SWITCH_IDX_CAST]]
; CHECK: return:
; CHECK-NEXT: ret i8 3
define i32 @covered_switch_with_bit_tests(i3) {
; CHECK-LABEL: @covered_switch_with_bit_tests(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i3 [[TMP0:%.*]], -4
-; CHECK-NEXT: [[SWITCH_MASKINDEX:%.*]] = zext i3 [[SWITCH_TABLEIDX]] to i8
-; CHECK-NEXT: [[SWITCH_SHIFTED:%.*]] = lshr i8 -61, [[SWITCH_MASKINDEX]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i3 [[TMP0:%.*]], -2
+; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_HOLE_CHECK:%.*]], label [[L6:%.*]]
+; CHECK: switch.hole_check:
+; CHECK-NEXT: [[TMP2:%.*]] = sub i3 [[TMP0]], 2
+; CHECK-NEXT: [[SWITCH_MASKINDEX:%.*]] = zext i3 [[TMP2]] to i8
+; CHECK-NEXT: [[SWITCH_SHIFTED:%.*]] = lshr i8 15, [[SWITCH_MASKINDEX]]
; CHECK-NEXT: [[SWITCH_LOBIT:%.*]] = trunc i8 [[SWITCH_SHIFTED]] to i1
-; CHECK-NEXT: br i1 [[SWITCH_LOBIT]], label [[SWITCH_LOOKUP:%.*]], label [[L6:%.*]]
+; CHECK-NEXT: br i1 [[SWITCH_LOBIT]], label [[SWITCH_LOOKUP:%.*]], label [[L6]]
; CHECK: switch.lookup:
-; CHECK-NEXT: [[SWITCH_TABLEIDX_ZEXT:%.*]] = zext i3 [[SWITCH_TABLEIDX]] to i4
-; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [8 x i32], [8 x i32]* @switch.table.covered_switch_with_bit_tests, i32 0, i4 [[SWITCH_TABLEIDX_ZEXT]]
+; CHECK-NEXT: [[SWITCH_TABLEIDX_ZEXT:%.*]] = zext i3 [[TMP2]] to i4
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @switch.table.covered_switch_with_bit_tests, i32 0, i4 [[SWITCH_TABLEIDX_ZEXT]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: br label [[L6]]
; CHECK: l6:
-; CHECK-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ]
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 0, [[SWITCH_HOLE_CHECK]] ], [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
; Optimization shouldn't trigger; not an arithmetic progression
define i32 @test4(i32 %a) {
; CHECK-LABEL: @test4(
-; CHECK-NEXT: switch i32 [[A:%.*]], label [[DEF:%.*]] [
-; CHECK-NEXT: i32 97, label [[ONE:%.*]]
-; CHECK-NEXT: i32 102, label [[TWO:%.*]]
-; CHECK-NEXT: i32 105, label [[THREE:%.*]]
-; CHECK-NEXT: i32 109, label [[THREE]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 97
+; CHECK-NEXT: switch i32 [[TMP1]], label [[DEF:%.*]] [
+; CHECK-NEXT: i32 0, label [[ONE:%.*]]
+; CHECK-NEXT: i32 5, label [[TWO:%.*]]
+; CHECK-NEXT: i32 8, label [[THREE:%.*]]
+; CHECK-NEXT: i32 12, label [[THREE]]
; CHECK-NEXT: ]
; CHECK: def:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 8867, [[TMP0:%.*]] ], [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ]
; Optimization shouldn't trigger; not a power of two
define i32 @test5(i32 %a) {
; CHECK-LABEL: @test5(
-; CHECK-NEXT: switch i32 [[A:%.*]], label [[DEF:%.*]] [
-; CHECK-NEXT: i32 97, label [[ONE:%.*]]
-; CHECK-NEXT: i32 102, label [[TWO:%.*]]
-; CHECK-NEXT: i32 107, label [[THREE:%.*]]
-; CHECK-NEXT: i32 112, label [[THREE]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 97
+; CHECK-NEXT: switch i32 [[TMP1]], label [[DEF:%.*]] [
+; CHECK-NEXT: i32 0, label [[ONE:%.*]]
+; CHECK-NEXT: i32 5, label [[TWO:%.*]]
+; CHECK-NEXT: i32 10, label [[THREE:%.*]]
+; CHECK-NEXT: i32 15, label [[THREE]]
; CHECK-NEXT: ]
; CHECK: def:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 8867, [[TMP0:%.*]] ], [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ]
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: i32 6, label [[ONE:%.*]]
-; CHECK-NEXT: i32 7, label [[TWO:%.*]]
-; CHECK-NEXT: i32 0, label [[THREE:%.*]]
-; CHECK-NEXT: i32 2, label [[THREE]]
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[A:%.*]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = shl i32 [[A]], 31
+; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: switch i32 [[TMP3]], label [[DEF:%.*]] [
+; CHECK-NEXT: i32 9, label [[ONE:%.*]]
+; CHECK-NEXT: i32 10, label [[TWO:%.*]]
+; CHECK-NEXT: i32 3, label [[THREE:%.*]]
+; CHECK-NEXT: i32 5, label [[THREE]]
; CHECK-NEXT: ]
; CHECK: def:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 8867, [[TMP0:%.*]] ], [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ]
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
; 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
; 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
; 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
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
;; 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
; 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
;; 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