[SimplifyCFG] back out all SwitchInst commits

They caused the sanitizer builds to fail.

My suspicion is the change the countLeadingZeros().

llvm-svn: 361736
This commit is contained in:
Shawn Landden 2019-05-26 18:15:51 +00:00
parent bd324fa227
commit 343578759e
20 changed files with 1415 additions and 2627 deletions

View File

@ -51,14 +51,14 @@ enum ZeroBehavior {
namespace detail {
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
static unsigned count(T Val, ZeroBehavior) {
static std::size_t count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
if (Val & 0x1)
return 0;
// Bisection method.
unsigned ZeroBits = 0;
std::size_t ZeroBits = 0;
T Shift = std::numeric_limits<T>::digits >> 1;
T Mask = std::numeric_limits<T>::max() >> Shift;
while (Shift) {
@ -75,7 +75,7 @@ template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
#if __GNUC__ >= 4 || defined(_MSC_VER)
template <typename T> struct TrailingZerosCounter<T, 4> {
static unsigned count(T Val, ZeroBehavior ZB) {
static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
@ -91,7 +91,7 @@ template <typename T> struct TrailingZerosCounter<T, 4> {
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct TrailingZerosCounter<T, 8> {
static unsigned count(T Val, ZeroBehavior ZB) {
static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
@ -116,7 +116,7 @@ template <typename T> struct TrailingZerosCounter<T, 8> {
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
@ -125,12 +125,12 @@ unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
namespace detail {
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
static unsigned count(T Val, ZeroBehavior) {
static std::size_t count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
// Bisection method.
unsigned ZeroBits = 0;
std::size_t ZeroBits = 0;
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
T Tmp = Val >> Shift;
if (Tmp)
@ -144,7 +144,7 @@ template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
#if __GNUC__ >= 4 || defined(_MSC_VER)
template <typename T> struct LeadingZerosCounter<T, 4> {
static unsigned count(T Val, ZeroBehavior ZB) {
static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
@ -160,7 +160,7 @@ template <typename T> struct LeadingZerosCounter<T, 4> {
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct LeadingZerosCounter<T, 8> {
static unsigned count(T Val, ZeroBehavior ZB) {
static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
@ -185,7 +185,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
@ -458,7 +458,7 @@ inline uint64_t ByteSwap_64(uint64_t Value) {
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
@ -474,7 +474,7 @@ unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
unsigned countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");

View File

@ -1147,7 +1147,7 @@ void AMDGPUAsmPrinter::getAmdKernelCode(amd_kernel_code_t &Out,
// These alignment values are specified in powers of two, so alignment =
// 2^n. The minimum alignment is 2^4 = 16.
Out.kernarg_segment_alignment = std::max<size_t>(4,
Out.kernarg_segment_alignment = std::max((size_t)4,
countTrailingZeros(MaxKernArgAlign));
}

View File

@ -5309,9 +5309,9 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
for (SwitchInst::CaseIt E = SI->case_end(); CI != E; ++CI) {
ConstantInt *CaseVal = CI->getCaseValue();
if (CaseVal->getValue().ult(MinCaseVal->getValue()))
if (CaseVal->getValue().slt(MinCaseVal->getValue()))
MinCaseVal = CaseVal;
if (CaseVal->getValue().ugt(MaxCaseVal->getValue()))
if (CaseVal->getValue().sgt(MaxCaseVal->getValue()))
MaxCaseVal = CaseVal;
// Resulting value at phi nodes for this case value.
@ -5337,7 +5337,8 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
}
uint64_t NumResults = ResultLists[PHIs[0]].size();
uint64_t TableSize = MaxCaseVal->getValue().getLimitedValue() + 1;
APInt RangeSpread = MaxCaseVal->getValue() - MinCaseVal->getValue();
uint64_t TableSize = RangeSpread.getLimitedValue() + 1;
bool TableHasHoles = (NumResults < TableSize);
// If the table has holes, we need a constant result for the default case
@ -5372,7 +5373,12 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
// Compute the table index value.
Builder.SetInsertPoint(SI);
Value *TableIndex = SI->getCondition();
Value *TableIndex;
if (MinCaseVal->isNullValue())
TableIndex = SI->getCondition();
else
TableIndex = Builder.CreateSub(SI->getCondition(), MinCaseVal,
"switch.tableidx");
// Compute the maximum table size representable by the integer type we are
// switching upon.
@ -5412,10 +5418,6 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
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));
@ -5459,11 +5461,8 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
// 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();
// 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);
SwitchLookupTable Table(Mod, TableSize, MinCaseVal, ResultList, DV, DL,
FuncName);
Value *Result = Table.BuildLookup(TableIndex, Builder);
@ -5508,6 +5507,17 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &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.
///
@ -5519,83 +5529,58 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
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());
unsigned BitWidth = CondTy->getIntegerBitWidth();
if (BitWidth > 64 || !DL.fitsInLegalInteger(BitWidth))
if (CondTy->getIntegerBitWidth() > 64 ||
!DL.fitsInLegalInteger(CondTy->getIntegerBitWidth()))
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;
// We organize the range to start from 0, if it is not already close.
SmallVector<uint64_t, 4> Values;
// 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;
for (auto &C : SI->cases())
Values.push_back(C.getCaseValue()->getValue().getLimitedValue());
Values.push_back(C.getCaseValue()->getValue().getSExtValue());
llvm::sort(Values);
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];
}
}
// If the switch is already dense, there's nothing useful to do here.
if (isSwitchDense(Values))
return false;
// This transform can be done speculatively because it is so cheap - it
// results in a single rotate operation being inserted.
// 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);
// 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
// is bitwise only, we switch now to an unsigned representation.
uint64_t GCD = 0;
for (auto &V : Values)
GCD = GreatestCommonDivisor64(GCD, (uint64_t)V);
// This transform can be done speculatively because it is so cheap - it results
// in a single rotate operation being inserted. This can only happen if the
// factor extracted is a power of 2.
// FIXME: If the GCD is an odd number we can multiply by the multiplicative
// inverse of GCD and then perform this transform.
// FIXME: It's possible that optimizing a switch on powers of two might also
// be beneficial - flag values are often powers of two and we could use a CLZ
// as the key function.
if (GCD <= 1 || !isPowerOf2_64(GCD))
// No common divisor found or too expensive to compute key function.
return false;
// countTrailingZeros(0) returns 64. As Values is guaranteed to have more than
// one element and LLVM disallows duplicate cases, Shift is guaranteed to be
// less than 64.
unsigned Shift = 64;
// We need to store this from _before_ the transform
uint64_t BestIndexXor = Values[BestIndex];
unsigned Shift = Log2_64(GCD);
for (auto &V : Values)
Shift = std::min(Shift, countTrailingZeros(V ^ BestIndexXor));
assert(Shift < 64);
if (Shift > 0) {
MadeChanges = true;
for (auto &V : Values)
V >>= Shift;
}
V = (int64_t)((uint64_t)V >> Shift);
// We Xor against Values[] (any element will do) because the if we do not
// start at zero, but also don't meet the SubThreshold, then we still might
// share common rights bits, and if this transform succeeds
// then we should insert the subtraction anyways, because the rotate trick
// below to avoid a branch needs the shifted away bits to be zero.
// Now transform the values such that they start at zero and ascend. Do not
// do this if the shift reduces the lowest value to less than SubThreshold,
// or if the subtraction is less than SubThreshold and it does not enable a
// rotate.
uint64_t Base = 0;
if ((BestIndexXor >= SubThreshold && Shift == 0) ||
(Shift > countTrailingZeros(BestIndexXor) &&
Values[BestIndex] >= SubThreshold)) {
Base = BestIndexXor;
MadeChanges = true;
for (auto &V : Values)
V = (APInt(BitWidth, V) - Base).getLimitedValue();
}
if (!MadeChanges)
// We didn't do anything.
if (!isSwitchDense(Values))
// Transform didn't create a dense switch.
return false;
// The obvious transform is to shift the switch condition right and emit a
@ -5610,22 +5595,18 @@ static bool ReduceSwitchRange(SwitchInst *SI, IRBuilder<> &Builder,
auto *Ty = cast<IntegerType>(SI->getCondition()->getType());
Builder.SetInsertPoint(SI);
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);
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);
for (auto Case : SI->cases()) {
auto *Orig = Case.getCaseValue();
auto Sub = Orig->getValue() - Base;
Case.setValue(cast<ConstantInt>(ConstantInt::get(Ty, Sub.lshr(Shift))));
auto Sub = Orig->getValue() - APInt(Ty->getBitWidth(), Base);
Case.setValue(
cast<ConstantInt>(ConstantInt::get(Ty, Sub.lshr(ShiftC->getValue()))));
}
return true;
}
@ -5666,9 +5647,6 @@ bool SimplifyCFGOpt::SimplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
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
@ -5678,6 +5656,9 @@ bool SimplifyCFGOpt::SimplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
SwitchToLookupTable(SI, Builder, DL, TTI))
return requestResimplify();
if (ReduceSwitchRange(SI, Builder, DL, TTI))
return requestResimplify();
return false;
}

View File

@ -1,14 +1,11 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg -mtriple=arm -mattr=+v6t2 < %s | FileCheck %s
define i32 @ctlz(i32 %A) {
; CHECK-LABEL: @ctlz(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true)
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
; CHECK-NEXT: ret i32 [[SEL]]
entry:
%tobool = icmp eq i32 %A, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -24,12 +21,10 @@ cond.end:
define i32 @cttz(i32 %A) {
; CHECK-LABEL: @cttz(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true)
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
; CHECK-NEXT: ret i32 [[SEL]]
entry:
%tobool = icmp eq i32 %A, 0
br i1 %tobool, label %cond.end, label %cond.true

View File

@ -1,20 +1,11 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
;RUN: opt -S -simplifycfg -mtriple=arm < %s | FileCheck %s
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
; CHECK-LABEL: select_trunc_i64
; CHECK-NOT: br
; CHECK: select
; CHECK: select
define arm_aapcscc i32 @select_trunc_i64(i32 %a, i32 %b) {
; CHECK-LABEL: @select_trunc_i64(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[A:%.*]] to i64
; CHECK-NEXT: [[CONV1:%.*]] = sext i32 [[B:%.*]] to i64
; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[CONV1]], [[CONV]]
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[ADD]], 2147483647
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[ADD]], -2147483648
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TMP0]], i64 [[ADD]], i64 -2147483648
; CHECK-NEXT: [[EXTRACT_T:%.*]] = trunc i64 [[COND]] to i32
; CHECK-NEXT: [[COND8_OFF0:%.*]] = select i1 [[CMP]], i32 2147483647, i32 [[EXTRACT_T]]
; CHECK-NEXT: ret i32 [[COND8_OFF0]]
;
entry:
%conv = sext i32 %a to i64
%conv1 = sext i32 %b to i64

View File

@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg < %s | FileCheck %s
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
@ -16,28 +15,11 @@ target triple = "armv7a--none-eabi"
@g4 = external thread_local global i32, align 4
define i32* @test3(i32 %n) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[N:%.*]], 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: ]
; CHECK: sw.bb1:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.bb2:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.default:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32* [ @g4, [[SW_DEFAULT]] ], [ getelementptr inbounds (i32, i32* inttoptr (i32 mul (i32 ptrtoint (i32* @g3 to i32), i32 2) to i32*), i32 1), [[SW_BB2]] ], [ @g2, [[SW_BB1]] ], [ @g1, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32* [[RETVAL_0]]
;
entry:
switch i32 %n, label %sw.default [
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
]
sw.bb:

View File

@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg -switch-to-lookup -mtriple=arm -relocation-model=static < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE
; RUN: opt -S -simplifycfg -switch-to-lookup -mtriple=arm -relocation-model=pic < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE
; RUN: opt -S -simplifycfg -switch-to-lookup -mtriple=arm -relocation-model=ropi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE
@ -23,22 +22,11 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "armv7a--none-eabi"
define i32 @test1(i32 %n) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[N:%.*]], 3
; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; CHECK: switch.lookup:
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32], [3 x i32]* @switch.table.test1, i32 0, i32 [[N]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
; CHECK: return:
; CHECK-NEXT: ret i32 15498
;
entry:
switch i32 %n, label %sw.default [
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
]
sw.bb:
@ -65,39 +53,11 @@ return:
define i32* @test2(i32 %n) {
; ENABLE-LABEL: @test2(
; ENABLE-NEXT: entry:
; ENABLE-NEXT: [[TMP0:%.*]] = icmp ult i32 [[N:%.*]], 3
; ENABLE-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; ENABLE: switch.lookup:
; ENABLE-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32*], [3 x i32*]* @switch.table.test2, i32 0, i32 [[N]]
; ENABLE-NEXT: [[SWITCH_LOAD:%.*]] = load i32*, i32** [[SWITCH_GEP]]
; ENABLE-NEXT: ret i32* [[SWITCH_LOAD]]
; ENABLE: return:
; ENABLE-NEXT: ret i32* @c4
;
; DISABLE-LABEL: @test2(
; DISABLE-NEXT: entry:
; DISABLE-NEXT: switch i32 [[N:%.*]], label [[SW_DEFAULT:%.*]] [
; DISABLE-NEXT: i32 0, label [[RETURN:%.*]]
; DISABLE-NEXT: i32 1, label [[SW_BB1:%.*]]
; DISABLE-NEXT: i32 2, label [[SW_BB2:%.*]]
; DISABLE-NEXT: ]
; DISABLE: sw.bb1:
; DISABLE-NEXT: br label [[RETURN]]
; DISABLE: sw.bb2:
; DISABLE-NEXT: br label [[RETURN]]
; DISABLE: sw.default:
; DISABLE-NEXT: br label [[RETURN]]
; DISABLE: return:
; DISABLE-NEXT: [[RETVAL_0:%.*]] = phi i32* [ @c4, [[SW_DEFAULT]] ], [ @c3, [[SW_BB2]] ], [ @c2, [[SW_BB1]] ], [ @c1, [[ENTRY:%.*]] ]
; DISABLE-NEXT: ret i32* [[RETVAL_0]]
;
entry:
switch i32 %n, label %sw.default [
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
]
sw.bb:
@ -123,39 +83,11 @@ return:
@g4 = external global i32, align 4
define i32* @test3(i32 %n) {
; ENABLE-LABEL: @test3(
; ENABLE-NEXT: entry:
; ENABLE-NEXT: [[TMP0:%.*]] = icmp ult i32 [[N:%.*]], 3
; ENABLE-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
; ENABLE: switch.lookup:
; ENABLE-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32*], [3 x i32*]* @switch.table.test3, i32 0, i32 [[N]]
; ENABLE-NEXT: [[SWITCH_LOAD:%.*]] = load i32*, i32** [[SWITCH_GEP]]
; ENABLE-NEXT: ret i32* [[SWITCH_LOAD]]
; ENABLE: return:
; ENABLE-NEXT: ret i32* @g4
;
; DISABLE-LABEL: @test3(
; DISABLE-NEXT: entry:
; DISABLE-NEXT: switch i32 [[N:%.*]], label [[SW_DEFAULT:%.*]] [
; DISABLE-NEXT: i32 0, label [[RETURN:%.*]]
; DISABLE-NEXT: i32 1, label [[SW_BB1:%.*]]
; DISABLE-NEXT: i32 2, label [[SW_BB2:%.*]]
; DISABLE-NEXT: ]
; DISABLE: sw.bb1:
; DISABLE-NEXT: br label [[RETURN]]
; DISABLE: sw.bb2:
; DISABLE-NEXT: br label [[RETURN]]
; DISABLE: sw.default:
; DISABLE-NEXT: br label [[RETURN]]
; DISABLE: return:
; DISABLE-NEXT: [[RETVAL_0:%.*]] = phi i32* [ @g4, [[SW_DEFAULT]] ], [ @g3, [[SW_BB2]] ], [ @g2, [[SW_BB1]] ], [ @g1, [[ENTRY:%.*]] ]
; DISABLE-NEXT: ret i32* [[RETVAL_0]]
;
entry:
switch i32 %n, label %sw.default [
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 2, label %sw.bb2
]
sw.bb:
@ -182,26 +114,6 @@ declare i32 @f4(i32, i32)
declare i32 @f5(i32, i32)
define i32 @test4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[A:%.*]], label [[COND_FALSE6:%.*]] [
; CHECK-NEXT: i32 1, label [[COND_END11:%.*]]
; CHECK-NEXT: i32 2, label [[COND_END11_FOLD_SPLIT:%.*]]
; CHECK-NEXT: i32 3, label [[COND_END11_FOLD_SPLIT1:%.*]]
; CHECK-NEXT: ]
; CHECK: cond.false6:
; CHECK-NEXT: [[CMP7:%.*]] = icmp eq i32 [[A]], 4
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP7]], i32 (i32, i32)* @f4, i32 (i32, i32)* @f5
; CHECK-NEXT: br label [[COND_END11]]
; CHECK: cond.end11.fold.split:
; CHECK-NEXT: br label [[COND_END11]]
; CHECK: cond.end11.fold.split1:
; CHECK-NEXT: br label [[COND_END11]]
; CHECK: cond.end11:
; CHECK-NEXT: [[COND12:%.*]] = phi i32 (i32, i32)* [ @f1, [[ENTRY:%.*]] ], [ [[COND]], [[COND_FALSE6]] ], [ @f2, [[COND_END11_FOLD_SPLIT]] ], [ @f3, [[COND_END11_FOLD_SPLIT1]] ]
; CHECK-NEXT: [[CALL:%.*]] = call i32 [[COND12]](i32 [[B:%.*]], i32 [[C:%.*]])
; CHECK-NEXT: ret i32 [[CALL]]
;
entry:
%cmp = icmp eq i32 %a, 1
br i1 %cmp, label %cond.end11, label %cond.false

View File

@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -simplifycfg -switch-to-lookup -S %s | FileCheck %s
; RUN: opt -passes='simplify-cfg<switch-to-lookup>' -S %s | FileCheck %s
; rdar://15268442
@ -6,28 +5,24 @@
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin12.0.0"
; CHECK-LABEL: define i3 @coveredswitch_test(
; CHECK: entry:
; CHECK-NEXT: sub i3 %input, -4
; CHECK-NEXT: zext i3 %switch.tableidx to i24
; CHECK-NEXT: mul i24 %switch.cast, 3
; CHECK-NEXT: lshr i24 7507338, %switch.shiftamt
; CHECK-NEXT: trunc i24 %switch.downshift to i3
; CHECK-NEXT: ret i3 %switch.masked
define i3 @coveredswitch_test(i3 %input) {
; CHECK-LABEL: @coveredswitch_test(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i3 [[INPUT:%.*]], -2
; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[BB8:%.*]]
; CHECK: switch.lookup:
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i3 [[INPUT]] to i18
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul i18 [[SWITCH_CAST]], 3
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i18 42792, [[SWITCH_SHIFTAMT]]
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i18 [[SWITCH_DOWNSHIFT]] to i3
; CHECK-NEXT: ret i3 [[SWITCH_MASKED]]
; CHECK: bb8:
; CHECK-NEXT: ret i3 -2
;
entry:
switch i3 %input, label %bb8 [
i3 0, label %bb7
i3 1, label %bb
i3 2, label %bb3
i3 3, label %bb4
i3 4, label %bb5
i3 5, label %bb6
i3 0, label %bb7
i3 1, label %bb
i3 2, label %bb3
i3 3, label %bb4
i3 4, label %bb5
i3 5, label %bb6
]
bb: ; preds = %entry

View File

@ -1,38 +1,19 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; 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]
; CHECK-LABEL: foo
; CHECK-NOT: @switch.table.foo = 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: [[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]]
; CHECK: sw.bb2:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.bb3:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.default:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 15, [[SW_DEFAULT]] ], [ -1, [[SW_BB3]] ], [ 0, [[SW_BB2]] ], [ 123, [[SW_BB1]] ], [ 55, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[RETVAL_0]]
;
entry:
switch i32 %c, label %sw.default [
i32 42, label %return
i32 43, label %sw.bb1
i32 44, label %sw.bb2
i32 45, label %sw.bb3
i32 42, label %return
i32 43, label %sw.bb1
i32 44, label %sw.bb2
i32 45, label %sw.bb3
]
sw.bb1: br label %return
@ -46,24 +27,12 @@ return:
define i32 @bar(i32 %c) {
; CHECK-LABEL: @bar(
; CHECK-NEXT: entry:
; 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 [[TMP0]]
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]]
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
; CHECK: return:
; CHECK-NEXT: ret i32 15
;
entry:
switch i32 %c, label %sw.default [
i32 42, label %return
i32 43, label %sw.bb1
i32 44, label %sw.bb2
i32 45, label %sw.bb3
i32 42, label %return
i32 43, label %sw.bb1
i32 44, label %sw.bb2
i32 45, label %sw.bb3
]
sw.bb1: br label %return

View File

@ -1,31 +1,14 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg -mtriple=x86_64-unknown-unknown -mattr=+bmi < %s | FileCheck %s --check-prefix=ALL --check-prefix=BMI
; RUN: opt -S -simplifycfg -mtriple=x86_64-unknown-unknown -mattr=+lzcnt < %s | FileCheck %s --check-prefix=ALL --check-prefix=LZCNT
; RUN: opt -S -simplifycfg -mtriple=x86_64-unknown-unknown < %s | FileCheck %s --check-prefix=ALL --check-prefix=GENERIC
define i64 @test1(i64 %A) {
; BMI-LABEL: @test1(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
; BMI-NEXT: ret i64 [[COND]]
;
; LZCNT-LABEL: @test1(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
; LZCNT-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
; LZCNT-NEXT: ret i64 [[SPEC_SELECT]]
;
; GENERIC-LABEL: @test1(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
; GENERIC-NEXT: ret i64 [[COND]]
;
; ALL-LABEL: @test1(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %A, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %A, i1 true)
; ALL-NEXT: select i1 [[COND]], i64 64, i64 [[CTLZ]]
; ALL: ret
entry:
%tobool = icmp eq i64 %A, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -40,27 +23,11 @@ cond.end: ; preds = %entry, %cond.true
}
define i32 @test2(i32 %A) {
; BMI-LABEL: @test2(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true)
; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; BMI-NEXT: ret i32 [[COND]]
;
; LZCNT-LABEL: @test2(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true)
; LZCNT-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; LZCNT-NEXT: ret i32 [[SPEC_SELECT]]
;
; GENERIC-LABEL: @test2(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true)
; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; GENERIC-NEXT: ret i32 [[COND]]
;
; ALL-LABEL: @test2(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
; ALL-NEXT: select i1 [[COND]], i32 32, i32 [[CTLZ]]
; ALL: ret
entry:
%tobool = icmp eq i32 %A, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -76,27 +43,11 @@ cond.end: ; preds = %entry, %cond.true
define signext i16 @test3(i16 signext %A) {
; BMI-LABEL: @test3(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.ctlz.i16(i16 [[A]], i1 true)
; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
; BMI-NEXT: ret i16 [[COND]]
;
; LZCNT-LABEL: @test3(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.ctlz.i16(i16 [[A]], i1 true)
; LZCNT-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
; LZCNT-NEXT: ret i16 [[SPEC_SELECT]]
;
; GENERIC-LABEL: @test3(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.ctlz.i16(i16 [[A]], i1 true)
; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
; GENERIC-NEXT: ret i16 [[COND]]
;
; ALL-LABEL: @test3(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i16 %A, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i16 @llvm.ctlz.i16(i16 %A, i1 true)
; ALL-NEXT: select i1 [[COND]], i16 16, i16 [[CTLZ]]
; ALL: ret
entry:
%tobool = icmp eq i16 %A, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -112,27 +63,11 @@ cond.end: ; preds = %entry, %cond.true
define i64 @test1b(i64 %A) {
; BMI-LABEL: @test1b(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true)
; BMI-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
; BMI-NEXT: ret i64 [[SPEC_SELECT]]
;
; LZCNT-LABEL: @test1b(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true)
; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
; LZCNT-NEXT: ret i64 [[COND]]
;
; GENERIC-LABEL: @test1b(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true)
; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]]
; GENERIC-NEXT: ret i64 [[COND]]
;
; ALL-LABEL: @test1b(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %A, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %A, i1 true)
; ALL-NEXT: select i1 [[COND]], i64 64, i64 [[CTTZ]]
; ALL: ret
entry:
%tobool = icmp eq i64 %A, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -148,27 +83,11 @@ cond.end: ; preds = %entry, %cond.true
define i32 @test2b(i32 %A) {
; BMI-LABEL: @test2b(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true)
; BMI-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; BMI-NEXT: ret i32 [[SPEC_SELECT]]
;
; LZCNT-LABEL: @test2b(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true)
; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; LZCNT-NEXT: ret i32 [[COND]]
;
; GENERIC-LABEL: @test2b(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true)
; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]]
; GENERIC-NEXT: ret i32 [[COND]]
;
; ALL-LABEL: @test2b(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
; ALL-NEXT: select i1 [[COND]], i32 32, i32 [[CTTZ]]
; ALL: ret
entry:
%tobool = icmp eq i32 %A, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -184,27 +103,11 @@ cond.end: ; preds = %entry, %cond.true
define signext i16 @test3b(i16 signext %A) {
; BMI-LABEL: @test3b(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.cttz.i16(i16 [[A]], i1 true)
; BMI-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
; BMI-NEXT: ret i16 [[SPEC_SELECT]]
;
; LZCNT-LABEL: @test3b(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.cttz.i16(i16 [[A]], i1 true)
; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
; LZCNT-NEXT: ret i16 [[COND]]
;
; GENERIC-LABEL: @test3b(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.cttz.i16(i16 [[A]], i1 true)
; GENERIC-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]]
; GENERIC-NEXT: ret i16 [[COND]]
;
; ALL-LABEL: @test3b(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i16 %A, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i16 @llvm.cttz.i16(i16 %A, i1 true)
; ALL-NEXT: select i1 [[COND]], i16 16, i16 [[CTTZ]]
; ALL: ret
entry:
%tobool = icmp eq i16 %A, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -223,38 +126,14 @@ cond.end: ; preds = %entry, %cond.true
; for the target.
define i64 @test1e(i32 %x) {
; BMI-LABEL: @test1e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
; BMI-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 32, i64 [[PHITMP2]]
; BMI-NEXT: ret i64 [[COND]]
;
; LZCNT-LABEL: @test1e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; LZCNT-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; LZCNT: cond.true:
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
; LZCNT-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
; LZCNT-NEXT: br label [[COND_END]]
; LZCNT: cond.end:
; LZCNT-NEXT: [[COND:%.*]] = phi i64 [ [[PHITMP2]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; LZCNT-NEXT: ret i64 [[COND]]
;
; GENERIC-LABEL: @test1e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
; GENERIC-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i64 [ [[PHITMP2]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i64 [[COND]]
;
; ALL-LABEL: @test1e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %x, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %x, i1 true)
; ALL: [[ZEXT:%[A-Za-z0-9]+]] = zext i32 [[CTTZ]] to i64
; BMI-NEXT: select i1 [[COND]], i64 32, i64 [[ZEXT]]
; LZCNT-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i32 %x, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -270,38 +149,14 @@ cond.end: ; preds = %entry, %cond.true
}
define i32 @test2e(i64 %x) {
; BMI-LABEL: @test2e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
; BMI-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]]
; BMI-NEXT: ret i32 [[COND]]
;
; LZCNT-LABEL: @test2e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; LZCNT-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; LZCNT: cond.true:
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
; LZCNT-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
; LZCNT-NEXT: br label [[COND_END]]
; LZCNT: cond.end:
; LZCNT-NEXT: [[COND:%.*]] = phi i32 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; LZCNT-NEXT: ret i32 [[COND]]
;
; GENERIC-LABEL: @test2e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
; GENERIC-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i32 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i32 [[COND]]
;
; ALL-LABEL: @test2e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %x, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %x, i1 true)
; ALL: [[TRUNC:%[A-Za-z0-9]+]] = trunc i64 [[CTTZ]] to i32
; BMI-NEXT: select i1 [[COND]], i32 64, i32 [[TRUNC]]
; LZCNT-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i64 %x, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -317,38 +172,14 @@ cond.end: ; preds = %entry, %cond.true
}
define i64 @test3e(i32 %x) {
; BMI-LABEL: @test3e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; BMI-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; BMI: cond.true:
; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
; BMI-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
; BMI-NEXT: br label [[COND_END]]
; BMI: cond.end:
; BMI-NEXT: [[COND:%.*]] = phi i64 [ [[PHITMP2]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; BMI-NEXT: ret i64 [[COND]]
;
; LZCNT-LABEL: @test3e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
; LZCNT-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 32, i64 [[PHITMP2]]
; LZCNT-NEXT: ret i64 [[COND]]
;
; GENERIC-LABEL: @test3e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
; GENERIC-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i64 [ [[PHITMP2]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i64 [[COND]]
;
; ALL-LABEL: @test3e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %x, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
; ALL: [[ZEXT:%[A-Za-z0-9]+]] = zext i32 [[CTLZ]] to i64
; LZCNT-NEXT: select i1 [[COND]], i64 32, i64 [[ZEXT]]
; BMI-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i32 %x, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -364,38 +195,14 @@ cond.end: ; preds = %entry, %cond.true
}
define i32 @test4e(i64 %x) {
; BMI-LABEL: @test4e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; BMI-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; BMI: cond.true:
; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
; BMI-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
; BMI-NEXT: br label [[COND_END]]
; BMI: cond.end:
; BMI-NEXT: [[COND:%.*]] = phi i32 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; BMI-NEXT: ret i32 [[COND]]
;
; LZCNT-LABEL: @test4e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
; LZCNT-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]]
; LZCNT-NEXT: ret i32 [[COND]]
;
; GENERIC-LABEL: @test4e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
; GENERIC-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i32 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i32 [[COND]]
;
; ALL-LABEL: @test4e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %x, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %x, i1 true)
; ALL: [[TRUNC:%[A-Za-z0-9]+]] = trunc i64 [[CTLZ]] to i32
; LZCNT-NEXT: select i1 [[COND]], i32 64, i32 [[TRUNC]]
; BMI-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i64 %x, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -411,38 +218,14 @@ cond.end: ; preds = %entry, %cond.true
}
define i16 @test5e(i64 %x) {
; BMI-LABEL: @test5e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; BMI-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; BMI: cond.true:
; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
; BMI-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
; BMI-NEXT: br label [[COND_END]]
; BMI: cond.end:
; BMI-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; BMI-NEXT: ret i16 [[COND]]
;
; LZCNT-LABEL: @test5e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
; LZCNT-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 64, i16 [[CAST]]
; LZCNT-NEXT: ret i16 [[COND]]
;
; GENERIC-LABEL: @test5e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true)
; GENERIC-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i16 [[COND]]
;
; ALL-LABEL: @test5e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %x, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %x, i1 true)
; ALL: [[TRUNC:%[A-Za-z0-9]+]] = trunc i64 [[CTLZ]] to i16
; LZCNT-NEXT: select i1 [[COND]], i16 64, i16 [[TRUNC]]
; BMI-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i64 %x, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -458,38 +241,14 @@ cond.end: ; preds = %entry, %cond.true
}
define i16 @test6e(i32 %x) {
; BMI-LABEL: @test6e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; BMI-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; BMI: cond.true:
; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
; BMI-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
; BMI-NEXT: br label [[COND_END]]
; BMI: cond.end:
; BMI-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; BMI-NEXT: ret i16 [[COND]]
;
; LZCNT-LABEL: @test6e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
; LZCNT-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
; LZCNT-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 32, i16 [[CAST]]
; LZCNT-NEXT: ret i16 [[COND]]
;
; GENERIC-LABEL: @test6e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
; GENERIC-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i16 [[COND]]
;
; ALL-LABEL: @test6e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %x, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
; ALL: [[TRUNC:%[A-Za-z0-9]+]] = trunc i32 [[CTLZ]] to i16
; LZCNT-NEXT: select i1 [[COND]], i16 32, i16 [[TRUNC]]
; BMI-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i32 %x, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -505,38 +264,14 @@ cond.end: ; preds = %entry, %cond.true
}
define i16 @test7e(i64 %x) {
; BMI-LABEL: @test7e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
; BMI-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 64, i16 [[CAST]]
; BMI-NEXT: ret i16 [[COND]]
;
; LZCNT-LABEL: @test7e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; LZCNT-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; LZCNT: cond.true:
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
; LZCNT-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
; LZCNT-NEXT: br label [[COND_END]]
; LZCNT: cond.end:
; LZCNT-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; LZCNT-NEXT: ret i16 [[COND]]
;
; GENERIC-LABEL: @test7e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true)
; GENERIC-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 64, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i16 [[COND]]
;
; ALL-LABEL: @test7e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %x, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %x, i1 true)
; ALL: [[TRUNC:%[A-Za-z0-9]+]] = trunc i64 [[CTTZ]] to i16
; BMI-NEXT: select i1 [[COND]], i16 64, i16 [[TRUNC]]
; LZCNT-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i64 %x, 0
br i1 %tobool, label %cond.end, label %cond.true
@ -552,38 +287,14 @@ cond.end: ; preds = %entry, %cond.true
}
define i16 @test8e(i32 %x) {
; BMI-LABEL: @test8e(
; BMI-NEXT: entry:
; BMI-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; BMI-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
; BMI-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
; BMI-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 32, i16 [[CAST]]
; BMI-NEXT: ret i16 [[COND]]
;
; LZCNT-LABEL: @test8e(
; LZCNT-NEXT: entry:
; LZCNT-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; LZCNT-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; LZCNT: cond.true:
; LZCNT-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
; LZCNT-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
; LZCNT-NEXT: br label [[COND_END]]
; LZCNT: cond.end:
; LZCNT-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; LZCNT-NEXT: ret i16 [[COND]]
;
; GENERIC-LABEL: @test8e(
; GENERIC-NEXT: entry:
; GENERIC-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0
; GENERIC-NEXT: br i1 [[TOBOOL]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
; GENERIC: cond.true:
; GENERIC-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
; GENERIC-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16
; GENERIC-NEXT: br label [[COND_END]]
; GENERIC: cond.end:
; GENERIC-NEXT: [[COND:%.*]] = phi i16 [ [[CAST]], [[COND_TRUE]] ], [ 32, [[ENTRY:%.*]] ]
; GENERIC-NEXT: ret i16 [[COND]]
;
; ALL-LABEL: @test8e(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %x, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %x, i1 true)
; ALL: [[TRUNC:%[A-Za-z0-9]+]] = trunc i32 [[CTTZ]] to i16
; BMI-NEXT: select i1 [[COND]], i16 32, i16 [[TRUNC]]
; LZCNT-NOT: select
; GENERIC-NOT: select
; ALL: ret
entry:
%tobool = icmp eq i32 %x, 0
br i1 %tobool, label %cond.end, label %cond.true

View File

@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg -switch-to-lookup < %s -mtriple=x86_64-apple-darwin12.0.0 | FileCheck %s
; RUN: opt -S -passes='simplify-cfg<switch-to-lookup>' < %s -mtriple=x86_64-apple-darwin12.0.0 | FileCheck %s
@ -6,29 +5,25 @@
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin12.0.0"
; When we have a covered lookup table, make sure we don't delete PHINodes that
; are cached in PHIs.
; CHECK-LABEL: @test
; CHECK: entry:
; CHECK-NEXT: sub i3 %arg, -4
; CHECK-NEXT: zext i3 %switch.tableidx to i4
; CHECK-NEXT: getelementptr inbounds [8 x i64], [8 x i64]* @switch.table.test, i32 0, i4 %switch.tableidx.zext
; CHECK-NEXT: load i64, i64* %switch.gep
; CHECK-NEXT: add i64
; CHECK-NEXT: ret i64
define i64 @test(i3 %arg) {
; CHECK-LABEL: @test(
; CHECK-NEXT: entry:
; 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: 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:
switch i3 %arg, label %Default [
i3 -2, label %Label6
i3 1, label %Label1
i3 2, label %Label2
i3 3, label %Label3
i3 -4, label %Label4
i3 -3, label %Label5
i3 -2, label %Label6
i3 1, label %Label1
i3 2, label %Label2
i3 3, label %Label3
i3 -4, label %Label4
i3 -3, label %Label5
]
Default:

View File

@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg -switch-to-lookup < %s -mtriple=x86_64-apple-darwin12.0.0 | FileCheck %s
; RUN: opt -S -passes='simplify-cfg<switch-to-lookup>' < %s -mtriple=x86_64-apple-darwin12.0.0 | FileCheck %s
@ -6,18 +5,21 @@
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin12.0.0"
; When tableindex can't fit into i2, we should extend the type to i3.
; CHECK-LABEL: @_TFO6reduce1E5toRawfS0_FT_Si
; CHECK: entry:
; CHECK-NEXT: sub i2 %0, -2
; CHECK-NEXT: zext i2 %switch.tableidx to i3
; CHECK-NEXT: getelementptr inbounds [4 x i64], [4 x i64]* @switch.table._TFO6reduce1E5toRawfS0_FT_Si, i32 0, i3 %switch.tableidx.zext
; CHECK-NEXT: load i64, i64* %switch.gep
; CHECK-NEXT: ret i64 %switch.load
define i64 @_TFO6reduce1E5toRawfS0_FT_Si(i2) {
; CHECK-LABEL: @_TFO6reduce1E5toRawfS0_FT_Si(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i2 [[TMP0:%.*]] to i64
; CHECK-NEXT: ret i64 [[SWITCH_IDX_CAST]]
;
entry:
switch i2 %0, label %1 [
i2 0, label %2
i2 1, label %3
i2 -2, label %4
i2 -1, label %5
i2 0, label %2
i2 1, label %3
i2 -2, label %4
i2 -1, label %5
]
; <label>:1 ; preds = %entry

File diff suppressed because it is too large Load Diff

View File

@ -119,12 +119,11 @@ three:
; Optimization shouldn't trigger; not an arithmetic progression
define i32 @test4(i32 %a) {
; CHECK-LABEL: @test4(
; 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: 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: ]
; CHECK: def:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 8867, [[TMP0:%.*]] ], [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ]
@ -157,12 +156,11 @@ three:
; Optimization shouldn't trigger; not a power of two
define i32 @test5(i32 %a) {
; CHECK-LABEL: @test5(
; 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: 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: ]
; CHECK: def:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 8867, [[TMP0:%.*]] ], [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ]
@ -234,10 +232,10 @@ three:
define i8 @test7(i8 %a) optsize {
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[TMP1:%.*]] = lshr i8 [[A:%.*]], 2
; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[A]], 6
; CHECK-NEXT: [[TMP3:%.*]] = or i8 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = sub i8 [[TMP3]], 55
; 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: switch.lookup:
@ -309,14 +307,15 @@ three:
define i32 @test9(i32 %a) {
; CHECK-LABEL: @test9(
; 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: [[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: ]
; CHECK: def:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 8867, [[TMP0:%.*]] ], [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ]

View File

@ -1,22 +1,11 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt %s -S -passes='simplify-cfg<switch-to-lookup>' | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; RUN: opt %s -S -simplifycfg | FileCheck %s
declare void @foo(i32)
define void @test(i1 %a) {
; CHECK-LABEL: @test(
; 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: call void @foo(i32 1)
; CHECK-NEXT: ret void
; CHECK: false:
; CHECK-NEXT: call void @foo(i32 3)
; CHECK-NEXT: ret void
;
; CHECK-LABEL: @test
; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
switch i1 %a, label %default [i1 1, label %true
i1 0, label %false]
i1 0, label %false]
true:
call void @foo(i32 1)
ret void
@ -26,35 +15,14 @@ false:
default:
call void @foo(i32 2)
ret void
}
}
define void @test2(i2 %a) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: switch i2 [[A:%.*]], label [[DEFAULT1:%.*]] [
; CHECK-NEXT: i2 0, label [[CASE0:%.*]]
; CHECK-NEXT: i2 1, label [[CASE1:%.*]]
; CHECK-NEXT: i2 -2, label [[CASE2:%.*]]
; CHECK-NEXT: i2 -1, label [[CASE3:%.*]]
; CHECK-NEXT: ]
; CHECK: case0:
; CHECK-NEXT: call void @foo(i32 0)
; CHECK-NEXT: ret void
; CHECK: case1:
; CHECK-NEXT: call void @foo(i32 1)
; CHECK-NEXT: ret void
; CHECK: case2:
; CHECK-NEXT: call void @foo(i32 2)
; CHECK-NEXT: ret void
; CHECK: case3:
; CHECK-NEXT: call void @foo(i32 3)
; CHECK-NEXT: ret void
; CHECK: default1:
; CHECK-NEXT: unreachable
;
; CHECK-LABEL: @test2
switch i2 %a, label %default [i2 0, label %case0
i2 1, label %case1
i2 2, label %case2
i2 3, label %case3]
i2 1, label %case1
i2 2, label %case2
i2 3, label %case3]
case0:
call void @foo(i32 0)
ret void
@ -68,35 +36,19 @@ case3:
call void @foo(i32 3)
ret void
default:
; CHECK-LABEL: default1:
; CHECK-NEXT: unreachable
call void @foo(i32 4)
ret void
}
}
; This one is a negative test - we know the value of the default,
; but that's about it
define void @test3(i2 %a) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: switch i2 [[A:%.*]], label [[DEFAULT:%.*]] [
; CHECK-NEXT: i2 0, label [[CASE0:%.*]]
; CHECK-NEXT: i2 1, label [[CASE1:%.*]]
; CHECK-NEXT: i2 -2, label [[CASE2:%.*]]
; CHECK-NEXT: ]
; CHECK: case0:
; CHECK-NEXT: call void @foo(i32 0)
; CHECK-NEXT: ret void
; CHECK: case1:
; CHECK-NEXT: call void @foo(i32 1)
; CHECK-NEXT: ret void
; CHECK: case2:
; CHECK-NEXT: call void @foo(i32 2)
; CHECK-NEXT: ret void
; CHECK: default:
; CHECK-NEXT: call void @foo(i32 0)
; CHECK-NEXT: ret void
;
; CHECK-LABEL: @test3
switch i2 %a, label %default [i2 0, label %case0
i2 1, label %case1
i2 2, label %case2]
i2 1, label %case1
i2 2, label %case2]
case0:
call void @foo(i32 0)
@ -108,30 +60,18 @@ case2:
call void @foo(i32 2)
ret void
default:
; CHECK-LABEL: default:
; CHECK-NEXT: call void @foo
call void @foo(i32 0)
ret void
}
}
; Negative test - check for possible overflow when computing
; number of possible cases.
define void @test4(i128 %a) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: switch i128 [[A:%.*]], label [[DEFAULT:%.*]] [
; CHECK-NEXT: i128 0, label [[CASE0:%.*]]
; CHECK-NEXT: i128 1, label [[CASE1:%.*]]
; CHECK-NEXT: ]
; CHECK: case0:
; CHECK-NEXT: call void @foo(i32 0)
; CHECK-NEXT: ret void
; CHECK: case1:
; CHECK-NEXT: call void @foo(i32 1)
; CHECK-NEXT: ret void
; CHECK: default:
; CHECK-NEXT: call void @foo(i32 0)
; CHECK-NEXT: ret void
;
; CHECK-LABEL: @test4
switch i128 %a, label %default [i128 0, label %case0
i128 1, label %case1]
i128 1, label %case1]
case0:
call void @foo(i32 0)
@ -140,29 +80,20 @@ case1:
call void @foo(i32 1)
ret void
default:
; CHECK-LABEL: default:
; CHECK-NEXT: call void @foo
call void @foo(i32 0)
ret void
}
}
; All but one bit known zero
define void @test5(i8 %a) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[A:%.*]], 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: call void @foo(i32 1)
; CHECK-NEXT: ret void
; CHECK: false:
; CHECK-NEXT: call void @foo(i32 3)
; CHECK-NEXT: ret void
;
%cmp = icmp ult i8 %a, 2
; CHECK-LABEL: @test5
; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
%cmp = icmp ult i8 %a, 2
call void @llvm.assume(i1 %cmp)
switch i8 %a, label %default [i8 1, label %true
i8 0, label %false]
i8 0, label %false]
true:
call void @foo(i32 1)
ret void
@ -172,29 +103,18 @@ false:
default:
call void @foo(i32 2)
ret void
}
}
;; All but one bit known one
define void @test6(i8 %a) {
; CHECK-LABEL: @test6(
; 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: call void @foo(i32 1)
; CHECK-NEXT: ret void
; CHECK: false:
; CHECK-NEXT: call void @foo(i32 3)
; CHECK-NEXT: ret void
;
; CHECK-LABEL: @test6
; CHECK: @llvm.assume
; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
%and = and i8 %a, 254
%cmp = icmp eq i8 %and, 254
%cmp = icmp eq i8 %and, 254
call void @llvm.assume(i1 %cmp)
switch i8 %a, label %default [i8 255, label %true
i8 254, label %false]
i8 254, label %false]
true:
call void @foo(i32 1)
ret void
@ -209,26 +129,15 @@ default:
; Check that we can eliminate both dead cases and dead defaults
; within a single run of simplify-cfg
define void @test7(i8 %a) {
; CHECK-LABEL: @test7(
; 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: call void @foo(i32 1)
; CHECK-NEXT: ret void
; CHECK: false:
; CHECK-NEXT: call void @foo(i32 3)
; CHECK-NEXT: ret void
;
; CHECK-LABEL: @test7
; CHECK: @llvm.assume
; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
%and = and i8 %a, 254
%cmp = icmp eq i8 %and, 254
%cmp = icmp eq i8 %and, 254
call void @llvm.assume(i1 %cmp)
switch i8 %a, label %default [i8 255, label %true
i8 254, label %false
i8 0, label %also_dead]
i8 254, label %false
i8 0, label %also_dead]
true:
call void @foo(i32 1)
ret void
@ -245,33 +154,17 @@ default:
;; All but one bit known undef
;; Note: This is currently testing an optimization which doesn't trigger. The
;; case this is protecting against is that a bit could be assumed both zero
;; case this is protecting against is that a bit could be assumed both zero
;; *or* one given we know it's undef. ValueTracking doesn't do this today,
;; but it doesn't hurt to confirm.
define void @test8(i8 %a) {
; CHECK-LABEL: @test8(
; 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
;
; CHECK: switch i8
%and = and i8 %a, 254
%cmp = icmp eq i8 %and, undef
call void @llvm.assume(i1 %cmp)
switch i8 %a, label %default [i8 255, label %true
i8 254, label %false]
i8 254, label %false]
true:
call void @foo(i32 1)
ret void

View File

@ -4,10 +4,10 @@
define i32 @test1(i32 %x) nounwind {
; CHECK-LABEL: @test1(
; CHECK-NEXT: a:
; CHECK-NEXT: [[I:%.*]] = shl i32 [[X:%.*]], 1
; CHECK-NEXT: [[I:%.*]] = shl i32 %x, 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I]], 24
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND]], i32 5, i32 0
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
; CHECK-NEXT: [[DOT:%.*]] = select i1 [[COND]], i32 5, i32 0
; CHECK-NEXT: ret i32 [[DOT]]
;
%i = shl i32 %x, 1
switch i32 %i, label %a [
@ -48,19 +48,12 @@ c:
define i1 @repeated_signbits(i8 %condition) {
; CHECK-LABEL: @repeated_signbits(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[CONDITION:%.*]] to i32
; CHECK-NEXT: switch i32 [[SEXT]], label [[DEFAULT:%.*]] [
; CHECK-NEXT: i32 0, label [[A:%.*]]
; CHECK-NEXT: i32 127, label [[A]]
; CHECK-NEXT: i32 -128, label [[A]]
; CHECK-NEXT: i32 -1, label [[A]]
; CHECK: switch i32
; CHECK-DAG: i32 -128, label %a
; CHECK-DAG: i32 -1, label %a
; CHECK-DAG: i32 0, label %a
; CHECK-DAG: i32 127, label %a
; CHECK-NEXT: ]
; CHECK: a:
; CHECK-NEXT: [[MERGE:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ], [ false, [[DEFAULT]] ]
; CHECK-NEXT: ret i1 [[MERGE]]
; CHECK: default:
; CHECK-NEXT: br label [[A]]
;
entry:
%sext = sext i8 %condition to i32

View File

@ -1,158 +1,141 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -simplifycfg -S | FileCheck -enable-var-scope %s
; Test basic folding to a conditional branch.
define i32 @foo(i64 %x, i64 %y) nounwind {
; CHECK-LABEL: @foo(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[EQ]], label [[B:%.*]], label [[SWITCH:%.*]]
; CHECK: switch:
; CHECK-NEXT: [[LT:%.*]] = icmp slt i64 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[LT]], label [[A:%.*]], label [[B]]
; CHECK: a:
; CHECK-NEXT: tail call void @bees.a() #0
; CHECK-NEXT: ret i32 1
; CHECK: b:
; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 0, [[SWITCH]] ], [ 2, [[ENTRY:%.*]] ]
; CHECK-NEXT: tail call void @bees.b() #0
; CHECK-NEXT: ret i32 [[RETVAL]]
;
entry:
%eq = icmp eq i64 %x, %y
br i1 %eq, label %b, label %switch
%eq = icmp eq i64 %x, %y
br i1 %eq, label %b, label %switch
switch:
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 0, i32 2
switch i32 %qux, label %bees [
i32 0, label %a
i32 1, label %b
i32 2, label %b
]
%lt = icmp slt i64 %x, %y
; CHECK: br i1 %lt, label %a, label %b
%qux = select i1 %lt, i32 0, i32 2
switch i32 %qux, label %bees [
i32 0, label %a
i32 1, label %b
i32 2, label %b
]
a:
tail call void @bees.a() nounwind
ret i32 1
tail call void @bees.a() nounwind
ret i32 1
; CHECK: b:
; CHECK-NEXT: %retval = phi i32 [ 0, %switch ], [ 2, %entry ]
b:
%retval = phi i32 [0, %switch], [0, %switch], [2, %entry]
tail call void @bees.b() nounwind
ret i32 %retval
%retval = phi i32 [0, %switch], [0, %switch], [2, %entry]
tail call void @bees.b() nounwind
ret i32 %retval
; CHECK-NOT: bees:
bees:
tail call void @llvm.trap() nounwind
unreachable
tail call void @llvm.trap() nounwind
unreachable
}
; Test basic folding to an unconditional branch.
define i32 @bar(i64 %x, i64 %y) nounwind {
; CHECK-LABEL: @bar(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @bees.a() #0
; CHECK-NEXT: ret i32 0
;
entry:
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 0, i32 2
switch i32 %qux, label %bees [
i32 0, label %a
i32 1, label %b
i32 2, label %a
]
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @bees.a() [[$NUW:#[0-9]+]]
; CHECK-NEXT: ret i32 0
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 0, i32 2
switch i32 %qux, label %bees [
i32 0, label %a
i32 1, label %b
i32 2, label %a
]
a:
%retval = phi i32 [0, %entry], [0, %entry], [1, %b]
tail call void @bees.a() nounwind
ret i32 0
%retval = phi i32 [0, %entry], [0, %entry], [1, %b]
tail call void @bees.a() nounwind
ret i32 0
b:
tail call void @bees.b() nounwind
br label %a
tail call void @bees.b() nounwind
br label %a
bees:
tail call void @llvm.trap() nounwind
unreachable
tail call void @llvm.trap() nounwind
unreachable
}
; Test the edge case where both values from the select are the default case.
define void @bazz(i64 %x, i64 %y) nounwind {
; CHECK-LABEL: @bazz(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @bees.b() #0
; CHECK-NEXT: ret void
;
entry:
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 10, i32 12
switch i32 %qux, label %b [
i32 0, label %a
i32 1, label %bees
i32 2, label %bees
]
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @bees.b() [[$NUW]]
; CHECK-NEXT: ret void
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 10, i32 12
switch i32 %qux, label %b [
i32 0, label %a
i32 1, label %bees
i32 2, label %bees
]
a:
tail call void @bees.a() nounwind
ret void
tail call void @bees.a() nounwind
ret void
b:
tail call void @bees.b() nounwind
ret void
tail call void @bees.b() nounwind
ret void
bees:
tail call void @llvm.trap()
unreachable
tail call void @llvm.trap()
unreachable
}
; Test the edge case where both values from the select are equal.
define void @quux(i64 %x, i64 %y) nounwind {
; CHECK-LABEL: @quux(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @bees.a() #0
; CHECK-NEXT: ret void
;
entry:
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 0, i32 0
switch i32 %qux, label %b [
i32 0, label %a
i32 1, label %bees
i32 2, label %bees
]
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @bees.a() [[$NUW]]
; CHECK-NEXT: ret void
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 0, i32 0
switch i32 %qux, label %b [
i32 0, label %a
i32 1, label %bees
i32 2, label %bees
]
a:
tail call void @bees.a() nounwind
ret void
tail call void @bees.a() nounwind
ret void
b:
tail call void @bees.b() nounwind
ret void
tail call void @bees.b() nounwind
ret void
bees:
tail call void @llvm.trap()
unreachable
tail call void @llvm.trap()
unreachable
}
; A final test, for phi node munging.
define i32 @xyzzy(i64 %x, i64 %y) {
; CHECK-LABEL: @xyzzy(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[LT:%.*]] = icmp slt i64 [[X]], [[Y]]
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[LT]], i32 -1, i32 1
; CHECK-NEXT: [[VAL:%.*]] = select i1 [[EQ]], i32 0, i32 [[SPEC_SELECT]]
; CHECK-NEXT: ret i32 [[VAL]]
;
entry:
%eq = icmp eq i64 %x, %y
br i1 %eq, label %r, label %cont
%eq = icmp eq i64 %x, %y
br i1 %eq, label %r, label %cont
cont:
%lt = icmp slt i64 %x, %y
%qux = select i1 %lt, i32 0, i32 2
switch i32 %qux, label %bees [
i32 0, label %a
i32 1, label %r
i32 2, label %r
]
; CHECK: %lt = icmp slt i64 %x, %y
%lt = icmp slt i64 %x, %y
; CHECK-NEXT: select i1 %lt, i32 -1, i32 1
%qux = select i1 %lt, i32 0, i32 2
switch i32 %qux, label %bees [
i32 0, label %a
i32 1, label %r
i32 2, label %r
]
r:
%val = phi i32 [0, %entry], [1, %cont], [1, %cont]
ret i32 %val
%val = phi i32 [0, %entry], [1, %cont], [1, %cont]
ret i32 %val
a:
ret i32 -1
ret i32 -1
; CHECK-NOT: bees:
bees:
tail call void @llvm.trap()
unreachable
tail call void @llvm.trap()
unreachable
}
declare void @llvm.trap() nounwind noreturn
declare void @bees.a() nounwind
declare void @bees.b() nounwind
; CHECK: attributes [[$NUW]] = { nounwind }
; CHECK: attributes #1 = { cold noreturn nounwind }

View File

@ -1,27 +1,18 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt %s -simplifycfg -S | FileCheck %s
declare i32 @f(i32)
define i32 @basic(i32 %x) {
; CHECK-LABEL: @basic(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -5
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3
; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[DEFAULT:%.*]]
; CHECK: default:
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @f(i32 0)
; CHECK-NEXT: ret i32 [[TMP0]]
; CHECK: a:
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @f(i32 1)
; CHECK-NEXT: ret i32 [[TMP1]]
;
; CHECK-LABEL: @basic
; CHECK: x.off = add i32 %x, -5
; CHECK: %switch = icmp ult i32 %x.off, 3
; CHECK: br i1 %switch, label %a, label %default
entry:
switch i32 %x, label %default [
i32 5, label %a
i32 6, label %a
i32 7, label %a
i32 5, label %a
i32 6, label %a
i32 7, label %a
]
default:
%0 = call i32 @f(i32 0)
@ -33,28 +24,20 @@ a:
define i32 @unreachable(i32 %x) {
; CHECK-LABEL: @unreachable(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -5
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3
; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[B:%.*]]
; CHECK: a:
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @f(i32 0)
; CHECK-NEXT: ret i32 [[TMP0]]
; CHECK: b:
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @f(i32 1)
; CHECK-NEXT: ret i32 [[TMP1]]
;
; CHECK-LABEL: @unreachable
; CHECK: x.off = add i32 %x, -5
; CHECK: %switch = icmp ult i32 %x.off, 3
; CHECK: br i1 %switch, label %a, label %b
entry:
switch i32 %x, label %unreachable [
i32 5, label %a
i32 6, label %a
i32 7, label %a
i32 10, label %b
i32 20, label %b
i32 30, label %b
i32 40, label %b
i32 5, label %a
i32 6, label %a
i32 7, label %a
i32 10, label %b
i32 20, label %b
i32 30, label %b
i32 40, label %b
]
unreachable:
unreachable
@ -68,28 +51,20 @@ b:
define i32 @unreachable2(i32 %x) {
; CHECK-LABEL: @unreachable2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -5
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3
; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[B:%.*]]
; CHECK: a:
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @f(i32 0)
; CHECK-NEXT: ret i32 [[TMP0]]
; CHECK: b:
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @f(i32 1)
; CHECK-NEXT: ret i32 [[TMP1]]
;
; CHECK-LABEL: @unreachable2
; CHECK: x.off = add i32 %x, -5
; CHECK: %switch = icmp ult i32 %x.off, 3
; CHECK: br i1 %switch, label %a, label %b
entry:
; Note: folding the most popular case destination into the default
; would prevent switch-to-icmp here.
switch i32 %x, label %unreachable [
i32 5, label %a
i32 6, label %a
i32 7, label %a
i32 10, label %b
i32 20, label %b
i32 5, label %a
i32 6, label %a
i32 7, label %a
i32 10, label %b
i32 20, label %b
]
unreachable:
unreachable

View File

@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg < %s | FileCheck %s
target datalayout="p:40:64:64:32"
@ -7,151 +6,102 @@ declare void @foo1()
declare void @foo2()
define void @test1(i32 %V) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
; CHECK-NEXT: i32 17, label [[T:%.*]]
; CHECK-NEXT: i32 4, label [[T]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test1(
; CHECK: switch i32 %V, label %F [
; CHECK: i32 17, label %T
; CHECK: i32 4, label %T
; CHECK: ]
}
define void @test1_ptr(i32* %V) {
; CHECK-LABEL: @test1_ptr(
; CHECK-NEXT: [[MAGICPTR:%.*]] = ptrtoint i32* [[V:%.*]] to i32
; CHECK-NEXT: switch i32 [[MAGICPTR]], label [[F:%.*]] [
; CHECK-NEXT: i32 17, label [[T:%.*]]
; CHECK-NEXT: i32 4, label [[T]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp eq i32* %V, inttoptr (i32 4 to i32*)
%C2 = icmp eq i32* %V, inttoptr (i32 17 to i32*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp eq i32* %V, inttoptr (i32 4 to i32*)
%C2 = icmp eq i32* %V, inttoptr (i32 17 to i32*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test1_ptr(
; DL: %magicptr = ptrtoint i32* %V to i32
; DL: switch i32 %magicptr, label %F [
; DL: i32 17, label %T
; DL: i32 4, label %T
; DL: ]
}
define void @test1_ptr_as1(i32 addrspace(1)* %V) {
; CHECK-LABEL: @test1_ptr_as1(
; CHECK-NEXT: [[MAGICPTR:%.*]] = ptrtoint i32 addrspace(1)* [[V:%.*]] to i32
; CHECK-NEXT: switch i32 [[MAGICPTR]], label [[F:%.*]] [
; CHECK-NEXT: i32 17, label [[T:%.*]]
; CHECK-NEXT: i32 4, label [[T]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 4 to i32 addrspace(1)*)
%C2 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 17 to i32 addrspace(1)*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 4 to i32 addrspace(1)*)
%C2 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 17 to i32 addrspace(1)*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test1_ptr_as1(
; DL: %magicptr = ptrtoint i32 addrspace(1)* %V to i16
; DL: switch i16 %magicptr, label %F [
; DL: i16 17, label %T
; DL: i16 4, label %T
; DL: ]
}
define void @test2(i32 %V) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[T:%.*]] [
; CHECK-NEXT: i32 17, label [[F:%.*]]
; CHECK-NEXT: i32 4, label [[F]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp ne i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp ne i32 %V, 17 ; <i1> [#uses=1]
%CN = and i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp ne i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp ne i32 %V, 17 ; <i1> [#uses=1]
%CN = and i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test2(
; CHECK: switch i32 %V, label %T [
; CHECK: i32 17, label %F
; CHECK: i32 4, label %F
; CHECK: ]
}
define void @test3(i32 %V) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
; CHECK-NEXT: i32 4, label [[T:%.*]]
; CHECK-NEXT: i32 17, label [[T]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
br i1 %C1, label %T, label %N
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
br i1 %C1, label %T, label %N
N: ; preds = %0
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
br i1 %C2, label %T, label %F
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
br i1 %C2, label %T, label %F
T: ; preds = %N, %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %N
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test3(
; CHECK: switch i32 %V, label %F [
; CHECK: i32 4, label %T
; CHECK: i32 17, label %T
; CHECK: ]
}
define i32 @test4(i8 zeroext %c) nounwind ssp noredzone {
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[LOR_RHS:%.*]] [
; CHECK-NEXT: i8 62, label [[LOR_END:%.*]]
; CHECK-NEXT: i8 34, label [[LOR_END]]
; CHECK-NEXT: i8 92, label [[LOR_END]]
; CHECK-NEXT: ]
; CHECK: lor.rhs:
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP0]] to i32
; CHECK-NEXT: ret i32 [[LOR_EXT]]
;
entry:
%cmp = icmp eq i8 %c, 62
br i1 %cmp, label %lor.end, label %lor.lhs.false
@ -169,28 +119,20 @@ lor.end: ; preds = %lor.rhs, %lor.lhs.f
%lor.ext = zext i1 %0 to i32
ret i32 %lor.ext
; CHECK-LABEL: @test4(
; CHECK: switch i8 %c, label %lor.rhs [
; CHECK: i8 62, label %lor.end
; CHECK: i8 34, label %lor.end
; CHECK: i8 92, label %lor.end
; CHECK: ]
}
define i32 @test5(i8 zeroext %c) nounwind ssp noredzone {
; CHECK-LABEL: @test5(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[LOR_RHS:%.*]] [
; CHECK-NEXT: i8 62, label [[LOR_END:%.*]]
; CHECK-NEXT: i8 34, label [[LOR_END]]
; CHECK-NEXT: i8 92, label [[LOR_END]]
; CHECK-NEXT: ]
; CHECK: lor.rhs:
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP0]] to i32
; CHECK-NEXT: ret i32 [[LOR_EXT]]
;
entry:
switch i8 %c, label %lor.rhs [
i8 62, label %lor.end
i8 34, label %lor.end
i8 92, label %lor.end
i8 62, label %lor.end
i8 34, label %lor.end
i8 92, label %lor.end
]
lor.rhs: ; preds = %entry
@ -201,63 +143,48 @@ lor.end: ; preds = %entry, %entry, %ent
%0 = phi i1 [ true, %entry ], [ %V, %lor.rhs ], [ true, %entry ], [ true, %entry ]
%lor.ext = zext i1 %0 to i32
ret i32 %lor.ext
; CHECK-LABEL: @test5(
; CHECK: switch i8 %c, label %lor.rhs [
; CHECK: i8 62, label %lor.end
; CHECK: i8 34, label %lor.end
; CHECK: i8 92, label %lor.end
; CHECK: ]
}
define i1 @test6({ i32, i32 }* %I) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP_1_I:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[I:%.*]], i64 0, i32 1
; CHECK-NEXT: [[TMP_2_I:%.*]] = load i32, i32* [[TMP_1_I]]
; CHECK-NEXT: [[TMP_2_I_OFF:%.*]] = add i32 [[TMP_2_I]], -14
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[TMP_2_I_OFF]], 6
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 true, i1 false
; CHECK-NEXT: ret i1 [[SPEC_SELECT]]
;
entry:
%tmp.1.i = getelementptr { i32, i32 }, { i32, i32 }* %I, i64 0, i32 1 ; <i32*> [#uses=1]
%tmp.2.i = load i32, i32* %tmp.1.i ; <i32> [#uses=6]
%tmp.2 = icmp eq i32 %tmp.2.i, 14 ; <i1> [#uses=1]
br i1 %tmp.2, label %shortcirc_done.4, label %shortcirc_next.0
%tmp.1.i = getelementptr { i32, i32 }, { i32, i32 }* %I, i64 0, i32 1 ; <i32*> [#uses=1]
%tmp.2.i = load i32, i32* %tmp.1.i ; <i32> [#uses=6]
%tmp.2 = icmp eq i32 %tmp.2.i, 14 ; <i1> [#uses=1]
br i1 %tmp.2, label %shortcirc_done.4, label %shortcirc_next.0
shortcirc_next.0: ; preds = %entry
%tmp.6 = icmp eq i32 %tmp.2.i, 15 ; <i1> [#uses=1]
br i1 %tmp.6, label %shortcirc_done.4, label %shortcirc_next.1
%tmp.6 = icmp eq i32 %tmp.2.i, 15 ; <i1> [#uses=1]
br i1 %tmp.6, label %shortcirc_done.4, label %shortcirc_next.1
shortcirc_next.1: ; preds = %shortcirc_next.0
%tmp.11 = icmp eq i32 %tmp.2.i, 16 ; <i1> [#uses=1]
br i1 %tmp.11, label %shortcirc_done.4, label %shortcirc_next.2
%tmp.11 = icmp eq i32 %tmp.2.i, 16 ; <i1> [#uses=1]
br i1 %tmp.11, label %shortcirc_done.4, label %shortcirc_next.2
shortcirc_next.2: ; preds = %shortcirc_next.1
%tmp.16 = icmp eq i32 %tmp.2.i, 17 ; <i1> [#uses=1]
br i1 %tmp.16, label %shortcirc_done.4, label %shortcirc_next.3
%tmp.16 = icmp eq i32 %tmp.2.i, 17 ; <i1> [#uses=1]
br i1 %tmp.16, label %shortcirc_done.4, label %shortcirc_next.3
shortcirc_next.3: ; preds = %shortcirc_next.2
%tmp.21 = icmp eq i32 %tmp.2.i, 18 ; <i1> [#uses=1]
br i1 %tmp.21, label %shortcirc_done.4, label %shortcirc_next.4
%tmp.21 = icmp eq i32 %tmp.2.i, 18 ; <i1> [#uses=1]
br i1 %tmp.21, label %shortcirc_done.4, label %shortcirc_next.4
shortcirc_next.4: ; preds = %shortcirc_next.3
%tmp.26 = icmp eq i32 %tmp.2.i, 19 ; <i1> [#uses=1]
br label %UnifiedReturnBlock
%tmp.26 = icmp eq i32 %tmp.2.i, 19 ; <i1> [#uses=1]
br label %UnifiedReturnBlock
shortcirc_done.4: ; preds = %shortcirc_next.3, %shortcirc_next.2, %shortcirc_next.1, %shortcirc_next.0, %entry
br label %UnifiedReturnBlock
br label %UnifiedReturnBlock
UnifiedReturnBlock: ; preds = %shortcirc_done.4, %shortcirc_next.4
%UnifiedRetVal = phi i1 [ %tmp.26, %shortcirc_next.4 ], [ true, %shortcirc_done.4 ] ; <i1> [#uses=1]
ret i1 %UnifiedRetVal
%UnifiedRetVal = phi i1 [ %tmp.26, %shortcirc_next.4 ], [ true, %shortcirc_done.4 ] ; <i1> [#uses=1]
ret i1 %UnifiedRetVal
; CHECK-LABEL: @test6(
; CHECK: %tmp.2.i.off = add i32 %tmp.2.i, -14
; CHECK: %switch = icmp ult i32 %tmp.2.i.off, 6
}
define void @test7(i8 zeroext %c, i32 %x) nounwind ssp noredzone {
; CHECK-LABEL: @test7(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
; CHECK: switch.early.test:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i8 99, label [[IF_THEN]]
; CHECK-NEXT: i8 97, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: tail call void @foo1() #2
; CHECK-NEXT: ret void
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ult i32 %x, 32
%cmp4 = icmp eq i8 %c, 97
@ -273,27 +200,17 @@ if.then: ; preds = %entry
if.end: ; preds = %entry
ret void
; CHECK-LABEL: @test7(
; CHECK: %cmp = icmp ult i32 %x, 32
; CHECK: br i1 %cmp, label %if.then, label %switch.early.test
; CHECK: switch.early.test:
; CHECK: switch i8 %c, label %if.end [
; CHECK: i8 99, label %if.then
; CHECK: i8 97, label %if.then
; CHECK: ]
}
define i32 @test8(i8 zeroext %c, i32 %x, i1 %C) nounwind ssp noredzone {
; CHECK-LABEL: @test8(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[N:%.*]], label [[IF_THEN:%.*]]
; CHECK: N:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]]
; CHECK: switch.early.test:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i8 99, label [[IF_THEN]]
; CHECK-NEXT: i8 97, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: [[A:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 42, [[SWITCH_EARLY_TEST]] ], [ 42, [[N]] ], [ 42, [[SWITCH_EARLY_TEST]] ]
; CHECK-NEXT: tail call void @foo1() #2
; CHECK-NEXT: ret i32 [[A]]
; CHECK: if.end:
; CHECK-NEXT: ret i32 0
;
entry:
br i1 %C, label %N, label %if.then
N:
@ -312,33 +229,17 @@ if.then: ; preds = %entry
if.end: ; preds = %entry
ret i32 0
; CHECK-LABEL: @test8(
; CHECK: switch.early.test:
; CHECK: switch i8 %c, label %if.end [
; CHECK: i8 99, label %if.then
; CHECK: i8 97, label %if.then
; CHECK: ]
; CHECK: %A = phi i32 [ 0, %entry ], [ 42, %switch.early.test ], [ 42, %N ], [ 42, %switch.early.test ]
}
;; This is "Example 7" from http://blog.regehr.org/archives/320
define i32 @test9(i8 zeroext %c) nounwind ssp noredzone {
; CHECK-LABEL: @test9(
; CHECK-NEXT: entry:
; 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 i8 [[C]], label [[LOR_RHS:%.*]] [
; CHECK-NEXT: i8 92, label [[LOR_END]]
; CHECK-NEXT: i8 62, label [[LOR_END]]
; CHECK-NEXT: i8 60, label [[LOR_END]]
; CHECK-NEXT: i8 59, label [[LOR_END]]
; CHECK-NEXT: i8 58, label [[LOR_END]]
; CHECK-NEXT: i8 46, label [[LOR_END]]
; CHECK-NEXT: i8 44, label [[LOR_END]]
; CHECK-NEXT: i8 34, label [[LOR_END]]
; CHECK-NEXT: i8 39, label [[LOR_END]]
; CHECK-NEXT: ]
; CHECK: lor.rhs:
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[SWITCH_EARLY_TEST]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY:%.*]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ]
; CHECK-NEXT: [[CONV46:%.*]] = zext i1 [[TMP0]] to i32
; CHECK-NEXT: ret i32 [[CONV46]]
;
entry:
%cmp = icmp ult i8 %c, 33
br i1 %cmp, label %lor.end, label %lor.lhs.false
@ -384,23 +285,25 @@ lor.end: ; preds = %lor.rhs, %lor.lhs.f
%conv46 = zext i1 %0 to i32
ret i32 %conv46
; CHECK-LABEL: @test9(
; CHECK: %cmp = icmp ult i8 %c, 33
; CHECK: br i1 %cmp, label %lor.end, label %switch.early.test
; CHECK: switch.early.test:
; CHECK: switch i8 %c, label %lor.rhs [
; CHECK: i8 92, label %lor.end
; CHECK: i8 62, label %lor.end
; CHECK: i8 60, label %lor.end
; CHECK: i8 59, label %lor.end
; CHECK: i8 58, label %lor.end
; CHECK: i8 46, label %lor.end
; CHECK: i8 44, label %lor.end
; CHECK: i8 34, label %lor.end
; CHECK: i8 39, label %lor.end
; CHECK: ]
}
define i32 @test10(i32 %mode, i1 %Cond) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]]
; CHECK: switch.early.test:
; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [
; CHECK-NEXT: i32 51, label [[F]]
; CHECK-NEXT: i32 0, label [[F]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 123, [[SWITCH_EARLY_TEST]] ], [ 324, [[F]] ]
; CHECK-NEXT: ret i32 [[MERGE]]
; CHECK: F:
; CHECK-NEXT: br label [[T]]
;
%A = icmp ne i32 %mode, 0
%B = icmp ne i32 %mode, 51
%C = and i1 %A, %B
@ -411,27 +314,17 @@ T:
F:
ret i32 324
; CHECK-LABEL: @test10(
; CHECK: br i1 %Cond, label %switch.early.test, label %F
; CHECK:switch.early.test:
; CHECK: switch i32 %mode, label %T [
; CHECK: i32 51, label %F
; CHECK: i32 0, label %F
; CHECK: ]
}
; PR8780
define i32 @test11(i32 %bar) nounwind {
; CHECK-LABEL: @test11(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[BAR:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i32 55, label [[RETURN:%.*]]
; CHECK-NEXT: i32 53, label [[RETURN]]
; CHECK-NEXT: i32 35, label [[RETURN]]
; CHECK-NEXT: i32 24, label [[RETURN]]
; CHECK-NEXT: i32 23, label [[RETURN]]
; CHECK-NEXT: i32 12, label [[RETURN]]
; CHECK-NEXT: i32 4, label [[RETURN]]
; CHECK-NEXT: ]
; CHECK: if.end:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 0, [[IF_END]] ], [ 1, [[ENTRY:%.*]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ]
; CHECK-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%cmp = icmp eq i32 %bar, 4
%cmp2 = icmp eq i32 %bar, 35
@ -460,21 +353,19 @@ return: ; preds = %if.end, %if.then
%retval.0 = phi i32 [ 1, %if.then ], [ 0, %if.end ]
ret i32 %retval.0
; CHECK-LABEL: @test11(
; CHECK: switch i32 %bar, label %if.end [
; CHECK: i32 55, label %return
; CHECK: i32 53, label %return
; CHECK: i32 35, label %return
; CHECK: i32 24, label %return
; CHECK: i32 23, label %return
; CHECK: i32 12, label %return
; CHECK: i32 4, label %return
; CHECK: ]
}
define void @test12() nounwind {
; CHECK-LABEL: @test12(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_OLD:%.*]] = icmp eq i32 undef, undef
; CHECK-NEXT: br i1 [[A_OLD]], label [[BB55_US_US:%.*]], label [[MALFORMED:%.*]]
; CHECK: bb55.us.us:
; CHECK-NEXT: [[B:%.*]] = icmp ugt i32 undef, undef
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 undef, undef
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[B]], [[A]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[BB55_US_US]], label [[MALFORMED]]
; CHECK: malformed:
; CHECK-NEXT: ret void
;
entry:
br label %bb49.us.us
@ -491,26 +382,12 @@ bb55.us.us:
malformed:
ret void
; CHECK-LABEL: @test12(
}
; test13 - handle switch formation with ult.
define void @test13(i32 %x) nounwind ssp noredzone {
; CHECK-LABEL: @test13(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[X:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i32 6, label [[IF_THEN:%.*]]
; CHECK-NEXT: i32 4, label [[IF_THEN]]
; CHECK-NEXT: i32 3, label [[IF_THEN]]
; CHECK-NEXT: i32 1, label [[IF_THEN]]
; CHECK-NEXT: i32 0, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: call void @foo1() #3
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ult i32 %x, 2
br i1 %cmp, label %if.then, label %lor.lhs.false3
@ -533,26 +410,18 @@ if.then: ; preds = %lor.lhs.false9, %lo
if.end: ; preds = %if.then, %lor.lhs.false9
ret void
; CHECK-LABEL: @test13(
; CHECK: switch i32 %x, label %if.end [
; CHECK: i32 6, label %if.then
; CHECK: i32 4, label %if.then
; CHECK: i32 3, label %if.then
; CHECK: i32 1, label %if.then
; CHECK: i32 0, label %if.then
; CHECK: ]
}
; test14 - handle switch formation with ult.
define void @test14(i32 %x) nounwind ssp noredzone {
; CHECK-LABEL: @test14(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[X:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i32 6, label [[IF_THEN:%.*]]
; CHECK-NEXT: i32 4, label [[IF_THEN]]
; CHECK-NEXT: i32 3, label [[IF_THEN]]
; CHECK-NEXT: i32 2, label [[IF_THEN]]
; CHECK-NEXT: i32 1, label [[IF_THEN]]
; CHECK-NEXT: i32 0, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: call void @foo1() #3
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ugt i32 %x, 2
br i1 %cmp, label %lor.lhs.false3, label %if.then
@ -575,15 +444,18 @@ if.then: ; preds = %lor.lhs.false9, %lo
if.end: ; preds = %if.then, %lor.lhs.false9
ret void
; CHECK-LABEL: @test14(
; CHECK: switch i32 %x, label %if.end [
; CHECK: i32 6, label %if.then
; CHECK: i32 4, label %if.then
; CHECK: i32 3, label %if.then
; CHECK: i32 1, label %if.then
; CHECK: i32 0, label %if.then
; CHECK: ]
}
; Don't crash on ginormous ranges.
define void @test15(i128 %x) nounwind {
; CHECK-LABEL: @test15(
; CHECK-NEXT: if.end:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i128 [[X:%.*]], 2
; CHECK-NEXT: ret void
;
%cmp = icmp ugt i128 %x, 2
br i1 %cmp, label %if.end, label %lor.false
@ -598,19 +470,18 @@ if.then:
if.end:
ret void
; CHECK-LABEL: @test15(
; CHECK-NOT: switch
; CHECK: ret void
}
; PR8675
; rdar://5134905
define zeroext i1 @test16(i32 %x) nounwind {
; CHECK-LABEL: @test16(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -1
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 true, i1 false
; CHECK-NEXT: ret i1 [[SPEC_SELECT]]
;
entry:
; CHECK-LABEL: @test16(
; CHECK: %x.off = add i32 %x, -1
; CHECK: %switch = icmp ult i32 %x.off, 3
%cmp.i = icmp eq i32 %x, 1
br i1 %cmp.i, label %lor.end, label %lor.lhs.false
@ -629,17 +500,6 @@ lor.end:
; Check that we don't turn an icmp into a switch where it's not useful.
define void @test17(i32 %x, i32 %y) {
; CHECK-LABEL: @test17(
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 3
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[Y:%.*]], 2
; CHECK-NEXT: [[OR_COND775:%.*]] = or i1 [[CMP]], [[SWITCH]]
; CHECK-NEXT: br i1 [[OR_COND775]], label [[LOR_LHS_FALSE8:%.*]], label [[RETURN:%.*]]
; CHECK: lor.lhs.false8:
; CHECK-NEXT: tail call void @foo1()
; CHECK-NEXT: ret void
; CHECK: return:
; CHECK-NEXT: ret void
;
%cmp = icmp ult i32 %x, 3
%switch = icmp ult i32 %y, 2
%or.cond775 = or i1 %cmp, %switch
@ -652,20 +512,13 @@ lor.lhs.false8:
return:
ret void
; CHECK-LABEL: @test17(
; CHECK-NOT: switch.early.test
; CHECK-NOT: switch i32
; CHECK: ret void
}
define void @test18(i32 %arg) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG_OFF:%.*]] = add i32 [[ARG:%.*]], -8
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[ARG_OFF]], 11
; CHECK-NEXT: br i1 [[SWITCH]], label [[BB19:%.*]], label [[BB20:%.*]]
; CHECK: bb19:
; CHECK-NEXT: tail call void @foo1()
; CHECK-NEXT: br label [[BB20]]
; CHECK: bb20:
; CHECK-NEXT: ret void
;
bb:
%tmp = and i32 %arg, -2
%tmp1 = icmp eq i32 %tmp, 8
@ -697,23 +550,12 @@ bb19: ; preds = %bb8, %bb
bb20: ; preds = %bb19, %bb8
ret void
; CHECK-LABEL: @test18(
; CHECK: %arg.off = add i32 %arg, -8
; CHECK: icmp ult i32 %arg.off, 11
}
define void @PR26323(i1 %tobool23, i32 %tmp3) {
; CHECK-LABEL: @PR26323(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL5:%.*]] = icmp ne i32 [[TMP3:%.*]], 0
; CHECK-NEXT: [[NEG14:%.*]] = and i32 [[TMP3]], -2
; CHECK-NEXT: [[CMP17:%.*]] = icmp ne i32 [[NEG14]], -1
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[TOBOOL5]], [[TOBOOL23:%.*]]
; CHECK-NEXT: [[OR_COND1:%.*]] = and i1 [[CMP17]], [[OR_COND]]
; CHECK-NEXT: br i1 [[OR_COND1]], label [[IF_END29:%.*]], label [[IF_THEN27:%.*]]
; CHECK: if.then27:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: unreachable
; CHECK: if.end29:
; CHECK-NEXT: ret void
;
entry:
%tobool5 = icmp ne i32 %tmp3, 0
%neg14 = and i32 %tmp3, -2
@ -730,19 +572,21 @@ if.end29: ; preds = %entry
ret void
}
; CHECK-LABEL: define void @PR26323(
; CHECK: %tobool5 = icmp ne i32 %tmp3, 0
; CHECK: %neg14 = and i32 %tmp3, -2
; CHECK: %cmp17 = icmp ne i32 %neg14, -1
; CHECK: %or.cond = and i1 %tobool5, %tobool23
; CHECK: %or.cond1 = and i1 %cmp17, %or.cond
; CHECK: br i1 %or.cond1, label %if.end29, label %if.then27
; Form a switch when and'ing a negated power of two
; CHECK-LABEL: define void @test19
; CHECK: switch i32 %arg, label %else [
; CHECK: i32 32, label %if
; CHECK: i32 13, label %if
; CHECK: i32 12, label %if
define void @test19(i32 %arg) {
; CHECK-LABEL: @test19(
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[ELSE:%.*]] [
; CHECK-NEXT: i32 32, label [[IF:%.*]]
; CHECK-NEXT: i32 13, label [[IF]]
; CHECK-NEXT: i32 12, label [[IF]]
; CHECK-NEXT: ]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = and i32 %arg, -2
%cmp1 = icmp eq i32 %and, 12
%cmp2 = icmp eq i32 %arg, 32
@ -758,19 +602,10 @@ else:
}
; Since %cmp1 is always false, a switch is never formed
; CHECK-LABEL: define void @test20
; CHECK-NOT: switch
; CHECK: ret void
define void @test20(i32 %arg) {
; CHECK-LABEL: @test20(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[ARG:%.*]], -2
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[AND]], 13
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[ARG]], 32
; CHECK-NEXT: [[PRED:%.*]] = or i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[PRED]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = and i32 %arg, -2
%cmp1 = icmp eq i32 %and, 13
%cmp2 = icmp eq i32 %arg, 32
@ -786,19 +621,11 @@ else:
}
; Form a switch when or'ing a power of two
; CHECK-LABEL: define void @test21
; CHECK: i32 32, label %else
; CHECK: i32 13, label %else
; CHECK: i32 12, label %else
define void @test21(i32 %arg) {
; CHECK-LABEL: @test21(
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[IF:%.*]] [
; CHECK-NEXT: i32 32, label [[ELSE:%.*]]
; CHECK-NEXT: i32 13, label [[ELSE]]
; CHECK-NEXT: i32 12, label [[ELSE]]
; CHECK-NEXT: ]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = or i32 %arg, 1
%cmp1 = icmp ne i32 %and, 13
%cmp2 = icmp ne i32 %arg, 32
@ -814,19 +641,10 @@ else:
}
; Since %cmp1 is always false, a switch is never formed
; CHECK-LABEL: define void @test22
; CHECK-NOT: switch
; CHECK: ret void
define void @test22(i32 %arg) {
; CHECK-LABEL: @test22(
; CHECK-NEXT: [[AND:%.*]] = or i32 [[ARG:%.*]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[AND]], 12
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[ARG]], 32
; CHECK-NEXT: [[PRED:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[PRED]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = or i32 %arg, 1
%cmp1 = icmp ne i32 %and, 12
%cmp2 = icmp ne i32 %arg, 32
@ -839,4 +657,4 @@ if:
else:
ret void
}
}

View File

@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -simplifycfg < %s | FileCheck %s
; RUN: opt -S -data-layout="p:32:32-p1:16:16" -simplifycfg < %s | FileCheck -check-prefix=CHECK -check-prefix=DL %s
@ -7,151 +6,102 @@ declare void @foo1()
declare void @foo2()
define void @test1(i32 %V) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
; CHECK-NEXT: i32 17, label [[T:%.*]]
; CHECK-NEXT: i32 4, label [[T]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test1(
; CHECK: switch i32 %V, label %F [
; CHECK: i32 17, label %T
; CHECK: i32 4, label %T
; CHECK: ]
}
define void @test1_ptr(i32* %V) {
; DL-LABEL: @test1_ptr(
; DL-NEXT: [[MAGICPTR:%.*]] = ptrtoint i32* [[V:%.*]] to i32
; DL-NEXT: switch i32 [[MAGICPTR]], label [[F:%.*]] [
; DL-NEXT: i32 17, label [[T:%.*]]
; DL-NEXT: i32 4, label [[T]]
; DL-NEXT: ]
; DL: T:
; DL-NEXT: call void @foo1()
; DL-NEXT: ret void
; DL: F:
; DL-NEXT: call void @foo2()
; DL-NEXT: ret void
;
%C1 = icmp eq i32* %V, inttoptr (i32 4 to i32*)
%C2 = icmp eq i32* %V, inttoptr (i32 17 to i32*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp eq i32* %V, inttoptr (i32 4 to i32*)
%C2 = icmp eq i32* %V, inttoptr (i32 17 to i32*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test1_ptr(
; DL: %magicptr = ptrtoint i32* %V to i32
; DL: switch i32 %magicptr, label %F [
; DL: i32 17, label %T
; DL: i32 4, label %T
; DL: ]
}
define void @test1_ptr_as1(i32 addrspace(1)* %V) {
; DL-LABEL: @test1_ptr_as1(
; DL-NEXT: [[MAGICPTR:%.*]] = ptrtoint i32 addrspace(1)* [[V:%.*]] to i16
; DL-NEXT: switch i16 [[MAGICPTR]], label [[F:%.*]] [
; DL-NEXT: i16 17, label [[T:%.*]]
; DL-NEXT: i16 4, label [[T]]
; DL-NEXT: ]
; DL: T:
; DL-NEXT: call void @foo1()
; DL-NEXT: ret void
; DL: F:
; DL-NEXT: call void @foo2()
; DL-NEXT: ret void
;
%C1 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 4 to i32 addrspace(1)*)
%C2 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 17 to i32 addrspace(1)*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 4 to i32 addrspace(1)*)
%C2 = icmp eq i32 addrspace(1)* %V, inttoptr (i32 17 to i32 addrspace(1)*)
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test1_ptr_as1(
; DL: %magicptr = ptrtoint i32 addrspace(1)* %V to i16
; DL: switch i16 %magicptr, label %F [
; DL: i16 17, label %T
; DL: i16 4, label %T
; DL: ]
}
define void @test2(i32 %V) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[T:%.*]] [
; CHECK-NEXT: i32 17, label [[F:%.*]]
; CHECK-NEXT: i32 4, label [[F]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp ne i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp ne i32 %V, 17 ; <i1> [#uses=1]
%CN = and i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
%C1 = icmp ne i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp ne i32 %V, 17 ; <i1> [#uses=1]
%CN = and i1 %C1, %C2 ; <i1> [#uses=1]
br i1 %CN, label %T, label %F
T: ; preds = %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %0
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test2(
; CHECK: switch i32 %V, label %T [
; CHECK: i32 17, label %F
; CHECK: i32 4, label %F
; CHECK: ]
}
define void @test3(i32 %V) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
; CHECK-NEXT: i32 4, label [[T:%.*]]
; CHECK-NEXT: i32 17, label [[T]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: F:
; CHECK-NEXT: call void @foo2()
; CHECK-NEXT: ret void
;
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
br i1 %C1, label %T, label %N
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
br i1 %C1, label %T, label %N
N: ; preds = %0
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
br i1 %C2, label %T, label %F
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
br i1 %C2, label %T, label %F
T: ; preds = %N, %0
call void @foo1( )
ret void
call void @foo1( )
ret void
F: ; preds = %N
call void @foo2( )
ret void
call void @foo2( )
ret void
; CHECK-LABEL: @test3(
; CHECK: switch i32 %V, label %F [
; CHECK: i32 4, label %T
; CHECK: i32 17, label %T
; CHECK: ]
}
define i32 @test4(i8 zeroext %c) nounwind ssp noredzone {
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[LOR_RHS:%.*]] [
; CHECK-NEXT: i8 62, label [[LOR_END:%.*]]
; CHECK-NEXT: i8 34, label [[LOR_END]]
; CHECK-NEXT: i8 92, label [[LOR_END]]
; CHECK-NEXT: ]
; CHECK: lor.rhs:
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP0]] to i32
; CHECK-NEXT: ret i32 [[LOR_EXT]]
;
entry:
%cmp = icmp eq i8 %c, 62
br i1 %cmp, label %lor.end, label %lor.lhs.false
@ -169,28 +119,20 @@ lor.end: ; preds = %lor.rhs, %lor.lhs.f
%lor.ext = zext i1 %0 to i32
ret i32 %lor.ext
; CHECK-LABEL: @test4(
; CHECK: switch i8 %c, label %lor.rhs [
; CHECK: i8 62, label %lor.end
; CHECK: i8 34, label %lor.end
; CHECK: i8 92, label %lor.end
; CHECK: ]
}
define i32 @test5(i8 zeroext %c) nounwind ssp noredzone {
; CHECK-LABEL: @test5(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[LOR_RHS:%.*]] [
; CHECK-NEXT: i8 62, label [[LOR_END:%.*]]
; CHECK-NEXT: i8 34, label [[LOR_END]]
; CHECK-NEXT: i8 92, label [[LOR_END]]
; CHECK-NEXT: ]
; CHECK: lor.rhs:
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP0]] to i32
; CHECK-NEXT: ret i32 [[LOR_EXT]]
;
entry:
switch i8 %c, label %lor.rhs [
i8 62, label %lor.end
i8 34, label %lor.end
i8 92, label %lor.end
i8 62, label %lor.end
i8 34, label %lor.end
i8 92, label %lor.end
]
lor.rhs: ; preds = %entry
@ -201,63 +143,48 @@ lor.end: ; preds = %entry, %entry, %ent
%0 = phi i1 [ true, %entry ], [ %V, %lor.rhs ], [ true, %entry ], [ true, %entry ]
%lor.ext = zext i1 %0 to i32
ret i32 %lor.ext
; CHECK-LABEL: @test5(
; CHECK: switch i8 %c, label %lor.rhs [
; CHECK: i8 62, label %lor.end
; CHECK: i8 34, label %lor.end
; CHECK: i8 92, label %lor.end
; CHECK: ]
}
define i1 @test6({ i32, i32 }* %I) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP_1_I:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[I:%.*]], i64 0, i32 1
; CHECK-NEXT: [[TMP_2_I:%.*]] = load i32, i32* [[TMP_1_I]]
; CHECK-NEXT: [[TMP_2_I_OFF:%.*]] = add i32 [[TMP_2_I]], -14
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[TMP_2_I_OFF]], 6
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 true, i1 false
; CHECK-NEXT: ret i1 [[SPEC_SELECT]]
;
entry:
%tmp.1.i = getelementptr { i32, i32 }, { i32, i32 }* %I, i64 0, i32 1 ; <i32*> [#uses=1]
%tmp.2.i = load i32, i32* %tmp.1.i ; <i32> [#uses=6]
%tmp.2 = icmp eq i32 %tmp.2.i, 14 ; <i1> [#uses=1]
br i1 %tmp.2, label %shortcirc_done.4, label %shortcirc_next.0
%tmp.1.i = getelementptr { i32, i32 }, { i32, i32 }* %I, i64 0, i32 1 ; <i32*> [#uses=1]
%tmp.2.i = load i32, i32* %tmp.1.i ; <i32> [#uses=6]
%tmp.2 = icmp eq i32 %tmp.2.i, 14 ; <i1> [#uses=1]
br i1 %tmp.2, label %shortcirc_done.4, label %shortcirc_next.0
shortcirc_next.0: ; preds = %entry
%tmp.6 = icmp eq i32 %tmp.2.i, 15 ; <i1> [#uses=1]
br i1 %tmp.6, label %shortcirc_done.4, label %shortcirc_next.1
%tmp.6 = icmp eq i32 %tmp.2.i, 15 ; <i1> [#uses=1]
br i1 %tmp.6, label %shortcirc_done.4, label %shortcirc_next.1
shortcirc_next.1: ; preds = %shortcirc_next.0
%tmp.11 = icmp eq i32 %tmp.2.i, 16 ; <i1> [#uses=1]
br i1 %tmp.11, label %shortcirc_done.4, label %shortcirc_next.2
%tmp.11 = icmp eq i32 %tmp.2.i, 16 ; <i1> [#uses=1]
br i1 %tmp.11, label %shortcirc_done.4, label %shortcirc_next.2
shortcirc_next.2: ; preds = %shortcirc_next.1
%tmp.16 = icmp eq i32 %tmp.2.i, 17 ; <i1> [#uses=1]
br i1 %tmp.16, label %shortcirc_done.4, label %shortcirc_next.3
%tmp.16 = icmp eq i32 %tmp.2.i, 17 ; <i1> [#uses=1]
br i1 %tmp.16, label %shortcirc_done.4, label %shortcirc_next.3
shortcirc_next.3: ; preds = %shortcirc_next.2
%tmp.21 = icmp eq i32 %tmp.2.i, 18 ; <i1> [#uses=1]
br i1 %tmp.21, label %shortcirc_done.4, label %shortcirc_next.4
%tmp.21 = icmp eq i32 %tmp.2.i, 18 ; <i1> [#uses=1]
br i1 %tmp.21, label %shortcirc_done.4, label %shortcirc_next.4
shortcirc_next.4: ; preds = %shortcirc_next.3
%tmp.26 = icmp eq i32 %tmp.2.i, 19 ; <i1> [#uses=1]
br label %UnifiedReturnBlock
%tmp.26 = icmp eq i32 %tmp.2.i, 19 ; <i1> [#uses=1]
br label %UnifiedReturnBlock
shortcirc_done.4: ; preds = %shortcirc_next.3, %shortcirc_next.2, %shortcirc_next.1, %shortcirc_next.0, %entry
br label %UnifiedReturnBlock
br label %UnifiedReturnBlock
UnifiedReturnBlock: ; preds = %shortcirc_done.4, %shortcirc_next.4
%UnifiedRetVal = phi i1 [ %tmp.26, %shortcirc_next.4 ], [ true, %shortcirc_done.4 ] ; <i1> [#uses=1]
ret i1 %UnifiedRetVal
%UnifiedRetVal = phi i1 [ %tmp.26, %shortcirc_next.4 ], [ true, %shortcirc_done.4 ] ; <i1> [#uses=1]
ret i1 %UnifiedRetVal
; CHECK-LABEL: @test6(
; CHECK: %tmp.2.i.off = add i32 %tmp.2.i, -14
; CHECK: %switch = icmp ult i32 %tmp.2.i.off, 6
}
define void @test7(i8 zeroext %c, i32 %x) nounwind ssp noredzone {
; CHECK-LABEL: @test7(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
; CHECK: switch.early.test:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i8 99, label [[IF_THEN]]
; CHECK-NEXT: i8 97, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: tail call void @foo1() #2
; CHECK-NEXT: ret void
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ult i32 %x, 32
%cmp4 = icmp eq i8 %c, 97
@ -273,27 +200,17 @@ if.then: ; preds = %entry
if.end: ; preds = %entry
ret void
; CHECK-LABEL: @test7(
; CHECK: %cmp = icmp ult i32 %x, 32
; CHECK: br i1 %cmp, label %if.then, label %switch.early.test
; CHECK: switch.early.test:
; CHECK: switch i8 %c, label %if.end [
; CHECK: i8 99, label %if.then
; CHECK: i8 97, label %if.then
; CHECK: ]
}
define i32 @test8(i8 zeroext %c, i32 %x, i1 %C) nounwind ssp noredzone {
; CHECK-LABEL: @test8(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[N:%.*]], label [[IF_THEN:%.*]]
; CHECK: N:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]]
; CHECK: switch.early.test:
; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i8 99, label [[IF_THEN]]
; CHECK-NEXT: i8 97, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: [[A:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 42, [[SWITCH_EARLY_TEST]] ], [ 42, [[N]] ], [ 42, [[SWITCH_EARLY_TEST]] ]
; CHECK-NEXT: tail call void @foo1() #2
; CHECK-NEXT: ret i32 [[A]]
; CHECK: if.end:
; CHECK-NEXT: ret i32 0
;
entry:
br i1 %C, label %N, label %if.then
N:
@ -312,33 +229,17 @@ if.then: ; preds = %entry
if.end: ; preds = %entry
ret i32 0
; CHECK-LABEL: @test8(
; CHECK: switch.early.test:
; CHECK: switch i8 %c, label %if.end [
; CHECK: i8 99, label %if.then
; CHECK: i8 97, label %if.then
; CHECK: ]
; CHECK: %A = phi i32 [ 0, %entry ], [ 42, %switch.early.test ], [ 42, %N ], [ 42, %switch.early.test ]
}
;; This is "Example 7" from http://blog.regehr.org/archives/320
define i32 @test9(i8 zeroext %c) nounwind ssp noredzone {
; CHECK-LABEL: @test9(
; CHECK-NEXT: entry:
; 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 i8 [[C]], label [[LOR_RHS:%.*]] [
; CHECK-NEXT: i8 92, label [[LOR_END]]
; CHECK-NEXT: i8 62, label [[LOR_END]]
; CHECK-NEXT: i8 60, label [[LOR_END]]
; CHECK-NEXT: i8 59, label [[LOR_END]]
; CHECK-NEXT: i8 58, label [[LOR_END]]
; CHECK-NEXT: i8 46, label [[LOR_END]]
; CHECK-NEXT: i8 44, label [[LOR_END]]
; CHECK-NEXT: i8 34, label [[LOR_END]]
; CHECK-NEXT: i8 39, label [[LOR_END]]
; CHECK-NEXT: ]
; CHECK: lor.rhs:
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[SWITCH_EARLY_TEST]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY:%.*]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ]
; CHECK-NEXT: [[CONV46:%.*]] = zext i1 [[TMP0]] to i32
; CHECK-NEXT: ret i32 [[CONV46]]
;
entry:
%cmp = icmp ult i8 %c, 33
br i1 %cmp, label %lor.end, label %lor.lhs.false
@ -384,23 +285,25 @@ lor.end: ; preds = %lor.rhs, %lor.lhs.f
%conv46 = zext i1 %0 to i32
ret i32 %conv46
; CHECK-LABEL: @test9(
; CHECK: %cmp = icmp ult i8 %c, 33
; CHECK: br i1 %cmp, label %lor.end, label %switch.early.test
; CHECK: switch.early.test:
; CHECK: switch i8 %c, label %lor.rhs [
; CHECK: i8 92, label %lor.end
; CHECK: i8 62, label %lor.end
; CHECK: i8 60, label %lor.end
; CHECK: i8 59, label %lor.end
; CHECK: i8 58, label %lor.end
; CHECK: i8 46, label %lor.end
; CHECK: i8 44, label %lor.end
; CHECK: i8 34, label %lor.end
; CHECK: i8 39, label %lor.end
; CHECK: ]
}
define i32 @test10(i32 %mode, i1 %Cond) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]]
; CHECK: switch.early.test:
; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [
; CHECK-NEXT: i32 51, label [[F]]
; CHECK-NEXT: i32 0, label [[F]]
; CHECK-NEXT: ]
; CHECK: T:
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ 123, [[SWITCH_EARLY_TEST]] ], [ 324, [[F]] ]
; CHECK-NEXT: ret i32 [[MERGE]]
; CHECK: F:
; CHECK-NEXT: br label [[T]]
;
%A = icmp ne i32 %mode, 0
%B = icmp ne i32 %mode, 51
%C = and i1 %A, %B
@ -411,27 +314,17 @@ T:
F:
ret i32 324
; CHECK-LABEL: @test10(
; CHECK: br i1 %Cond, label %switch.early.test, label %F
; CHECK:switch.early.test:
; CHECK: switch i32 %mode, label %T [
; CHECK: i32 51, label %F
; CHECK: i32 0, label %F
; CHECK: ]
}
; PR8780
define i32 @test11(i32 %bar) nounwind {
; CHECK-LABEL: @test11(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[BAR:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i32 55, label [[RETURN:%.*]]
; CHECK-NEXT: i32 53, label [[RETURN]]
; CHECK-NEXT: i32 35, label [[RETURN]]
; CHECK-NEXT: i32 24, label [[RETURN]]
; CHECK-NEXT: i32 23, label [[RETURN]]
; CHECK-NEXT: i32 12, label [[RETURN]]
; CHECK-NEXT: i32 4, label [[RETURN]]
; CHECK-NEXT: ]
; CHECK: if.end:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 0, [[IF_END]] ], [ 1, [[ENTRY:%.*]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ], [ 1, [[ENTRY]] ]
; CHECK-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%cmp = icmp eq i32 %bar, 4
%cmp2 = icmp eq i32 %bar, 35
@ -460,21 +353,19 @@ return: ; preds = %if.end, %if.then
%retval.0 = phi i32 [ 1, %if.then ], [ 0, %if.end ]
ret i32 %retval.0
; CHECK-LABEL: @test11(
; CHECK: switch i32 %bar, label %if.end [
; CHECK: i32 55, label %return
; CHECK: i32 53, label %return
; CHECK: i32 35, label %return
; CHECK: i32 24, label %return
; CHECK: i32 23, label %return
; CHECK: i32 12, label %return
; CHECK: i32 4, label %return
; CHECK: ]
}
define void @test12() nounwind {
; CHECK-LABEL: @test12(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_OLD:%.*]] = icmp eq i32 undef, undef
; CHECK-NEXT: br i1 [[A_OLD]], label [[BB55_US_US:%.*]], label [[MALFORMED:%.*]]
; CHECK: bb55.us.us:
; CHECK-NEXT: [[B:%.*]] = icmp ugt i32 undef, undef
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 undef, undef
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[B]], [[A]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[BB55_US_US]], label [[MALFORMED]]
; CHECK: malformed:
; CHECK-NEXT: ret void
;
entry:
br label %bb49.us.us
@ -491,26 +382,12 @@ bb55.us.us:
malformed:
ret void
; CHECK-LABEL: @test12(
}
; test13 - handle switch formation with ult.
define void @test13(i32 %x) nounwind ssp noredzone {
; CHECK-LABEL: @test13(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[X:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i32 6, label [[IF_THEN:%.*]]
; CHECK-NEXT: i32 4, label [[IF_THEN]]
; CHECK-NEXT: i32 3, label [[IF_THEN]]
; CHECK-NEXT: i32 1, label [[IF_THEN]]
; CHECK-NEXT: i32 0, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: call void @foo1() #3
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ult i32 %x, 2
br i1 %cmp, label %if.then, label %lor.lhs.false3
@ -533,26 +410,18 @@ if.then: ; preds = %lor.lhs.false9, %lo
if.end: ; preds = %if.then, %lor.lhs.false9
ret void
; CHECK-LABEL: @test13(
; CHECK: switch i32 %x, label %if.end [
; CHECK: i32 6, label %if.then
; CHECK: i32 4, label %if.then
; CHECK: i32 3, label %if.then
; CHECK: i32 1, label %if.then
; CHECK: i32 0, label %if.then
; CHECK: ]
}
; test14 - handle switch formation with ult.
define void @test14(i32 %x) nounwind ssp noredzone {
; CHECK-LABEL: @test14(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[X:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT: i32 6, label [[IF_THEN:%.*]]
; CHECK-NEXT: i32 4, label [[IF_THEN]]
; CHECK-NEXT: i32 3, label [[IF_THEN]]
; CHECK-NEXT: i32 2, label [[IF_THEN]]
; CHECK-NEXT: i32 1, label [[IF_THEN]]
; CHECK-NEXT: i32 0, label [[IF_THEN]]
; CHECK-NEXT: ]
; CHECK: if.then:
; CHECK-NEXT: call void @foo1() #3
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ugt i32 %x, 2
br i1 %cmp, label %lor.lhs.false3, label %if.then
@ -575,15 +444,18 @@ if.then: ; preds = %lor.lhs.false9, %lo
if.end: ; preds = %if.then, %lor.lhs.false9
ret void
; CHECK-LABEL: @test14(
; CHECK: switch i32 %x, label %if.end [
; CHECK: i32 6, label %if.then
; CHECK: i32 4, label %if.then
; CHECK: i32 3, label %if.then
; CHECK: i32 1, label %if.then
; CHECK: i32 0, label %if.then
; CHECK: ]
}
; Don't crash on ginormous ranges.
define void @test15(i128 %x) nounwind {
; CHECK-LABEL: @test15(
; CHECK-NEXT: if.end:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i128 [[X:%.*]], 2
; CHECK-NEXT: ret void
;
%cmp = icmp ugt i128 %x, 2
br i1 %cmp, label %if.end, label %lor.false
@ -598,19 +470,18 @@ if.then:
if.end:
ret void
; CHECK-LABEL: @test15(
; CHECK-NOT: switch
; CHECK: ret void
}
; PR8675
; rdar://5134905
define zeroext i1 @test16(i32 %x) nounwind {
; CHECK-LABEL: @test16(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -1
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 true, i1 false
; CHECK-NEXT: ret i1 [[SPEC_SELECT]]
;
entry:
; CHECK-LABEL: @test16(
; CHECK: %x.off = add i32 %x, -1
; CHECK: %switch = icmp ult i32 %x.off, 3
%cmp.i = icmp eq i32 %x, 1
br i1 %cmp.i, label %lor.end, label %lor.lhs.false
@ -629,17 +500,6 @@ lor.end:
; Check that we don't turn an icmp into a switch where it's not useful.
define void @test17(i32 %x, i32 %y) {
; CHECK-LABEL: @test17(
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 3
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[Y:%.*]], 2
; CHECK-NEXT: [[OR_COND775:%.*]] = or i1 [[CMP]], [[SWITCH]]
; CHECK-NEXT: br i1 [[OR_COND775]], label [[LOR_LHS_FALSE8:%.*]], label [[RETURN:%.*]]
; CHECK: lor.lhs.false8:
; CHECK-NEXT: tail call void @foo1()
; CHECK-NEXT: ret void
; CHECK: return:
; CHECK-NEXT: ret void
;
%cmp = icmp ult i32 %x, 3
%switch = icmp ult i32 %y, 2
%or.cond775 = or i1 %cmp, %switch
@ -652,20 +512,13 @@ lor.lhs.false8:
return:
ret void
; CHECK-LABEL: @test17(
; CHECK-NOT: switch.early.test
; CHECK-NOT: switch i32
; CHECK: ret void
}
define void @test18(i32 %arg) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG_OFF:%.*]] = add i32 [[ARG:%.*]], -8
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[ARG_OFF]], 11
; CHECK-NEXT: br i1 [[SWITCH]], label [[BB19:%.*]], label [[BB20:%.*]]
; CHECK: bb19:
; CHECK-NEXT: tail call void @foo1()
; CHECK-NEXT: br label [[BB20]]
; CHECK: bb20:
; CHECK-NEXT: ret void
;
bb:
%tmp = and i32 %arg, -2
%tmp1 = icmp eq i32 %tmp, 8
@ -697,23 +550,12 @@ bb19: ; preds = %bb8, %bb
bb20: ; preds = %bb19, %bb8
ret void
; CHECK-LABEL: @test18(
; CHECK: %arg.off = add i32 %arg, -8
; CHECK: icmp ult i32 %arg.off, 11
}
define void @PR26323(i1 %tobool23, i32 %tmp3) {
; CHECK-LABEL: @PR26323(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL5:%.*]] = icmp ne i32 [[TMP3:%.*]], 0
; CHECK-NEXT: [[NEG14:%.*]] = and i32 [[TMP3]], -2
; CHECK-NEXT: [[CMP17:%.*]] = icmp ne i32 [[NEG14]], -1
; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[TOBOOL5]], [[TOBOOL23:%.*]]
; CHECK-NEXT: [[OR_COND1:%.*]] = and i1 [[CMP17]], [[OR_COND]]
; CHECK-NEXT: br i1 [[OR_COND1]], label [[IF_END29:%.*]], label [[IF_THEN27:%.*]]
; CHECK: if.then27:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: unreachable
; CHECK: if.end29:
; CHECK-NEXT: ret void
;
entry:
%tobool5 = icmp ne i32 %tmp3, 0
%neg14 = and i32 %tmp3, -2
@ -730,20 +572,21 @@ if.end29: ; preds = %entry
ret void
}
; CHECK-LABEL: define void @PR26323(
; CHECK: %tobool5 = icmp ne i32 %tmp3, 0
; CHECK: %neg14 = and i32 %tmp3, -2
; CHECK: %cmp17 = icmp ne i32 %neg14, -1
; CHECK: %or.cond = and i1 %tobool5, %tobool23
; CHECK: %or.cond1 = and i1 %cmp17, %or.cond
; CHECK: br i1 %or.cond1, label %if.end29, label %if.then27
; Form a switch when and'ing a negated power of two
; CHECK-LABEL: define void @test19
; CHECK: switch i32 %arg, label %else [
; CHECK: i32 32, label %if
; CHECK: i32 13, label %if
; CHECK: i32 12, label %if
define void @test19(i32 %arg) {
; CHECK-LABEL: @test19(
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[ELSE:%.*]] [
; CHECK-NEXT: i32 32, label [[IF:%.*]]
; CHECK-NEXT: i32 13, label [[IF]]
; CHECK-NEXT: i32 12, label [[IF]]
; CHECK-NEXT: ]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = and i32 %arg, -2
%cmp1 = icmp eq i32 %and, 12
%cmp2 = icmp eq i32 %arg, 32
@ -759,19 +602,10 @@ else:
}
; Since %cmp1 is always false, a switch is never formed
; CHECK-LABEL: define void @test20
; CHECK-NOT: switch
; CHECK: ret void
define void @test20(i32 %arg) {
; CHECK-LABEL: @test20(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[ARG:%.*]], -2
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[AND]], 13
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[ARG]], 32
; CHECK-NEXT: [[PRED:%.*]] = or i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[PRED]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = and i32 %arg, -2
%cmp1 = icmp eq i32 %and, 13
%cmp2 = icmp eq i32 %arg, 32
@ -787,19 +621,11 @@ else:
}
; Form a switch when or'ing a power of two
; CHECK-LABEL: define void @test21
; CHECK: i32 32, label %else
; CHECK: i32 13, label %else
; CHECK: i32 12, label %else
define void @test21(i32 %arg) {
; CHECK-LABEL: @test21(
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[IF:%.*]] [
; CHECK-NEXT: i32 32, label [[ELSE:%.*]]
; CHECK-NEXT: i32 13, label [[ELSE]]
; CHECK-NEXT: i32 12, label [[ELSE]]
; CHECK-NEXT: ]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = or i32 %arg, 1
%cmp1 = icmp ne i32 %and, 13
%cmp2 = icmp ne i32 %arg, 32
@ -815,19 +641,10 @@ else:
}
; Since %cmp1 is always false, a switch is never formed
; CHECK-LABEL: define void @test22
; CHECK-NOT: switch
; CHECK: ret void
define void @test22(i32 %arg) {
; CHECK-LABEL: @test22(
; CHECK-NEXT: [[AND:%.*]] = or i32 [[ARG:%.*]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[AND]], 12
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[ARG]], 32
; CHECK-NEXT: [[PRED:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[PRED]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo1()
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: ret void
;
%and = or i32 %arg, 1
%cmp1 = icmp ne i32 %and, 12
%cmp2 = icmp ne i32 %arg, 32
@ -840,4 +657,4 @@ if:
else:
ret void
}
}