diff --git a/lib/Transforms/InstCombine/InstCombineSelect.cpp b/lib/Transforms/InstCombine/InstCombineSelect.cpp index 83a2f2c563f..df55e86f059 100644 --- a/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -617,26 +617,44 @@ Instruction *InstCombiner::visitSelectInstWithICmp(SelectInst &SI, } } - { + if (unsigned BitWidth = TrueVal->getType()->getScalarSizeInBits()) { + APInt MinSignedValue = APInt::getSignBit(BitWidth); Value *X; const APInt *Y, *C; - if (match(CmpLHS, m_And(m_Value(X), m_Power2(Y))) && + bool TrueWhenUnset; + bool IsBitTest = false; + if (ICmpInst::isEquality(Pred) && + match(CmpLHS, m_And(m_Value(X), m_Power2(Y))) && match(CmpRHS, m_Zero())) { + IsBitTest = true; + TrueWhenUnset = Pred == ICmpInst::ICMP_EQ; + } else if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, m_Zero())) { + X = CmpLHS; + Y = &MinSignedValue; + IsBitTest = true; + TrueWhenUnset = false; + } else if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, m_AllOnes())) { + X = CmpLHS; + Y = &MinSignedValue; + IsBitTest = true; + TrueWhenUnset = true; + } + if (IsBitTest) { Value *V = nullptr; // (X & Y) == 0 ? X : X ^ Y --> X & ~Y - if (Pred == ICmpInst::ICMP_EQ && TrueVal == X && + if (TrueWhenUnset && TrueVal == X && match(FalseVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C) V = Builder->CreateAnd(X, ~(*Y)); // (X & Y) != 0 ? X ^ Y : X --> X & ~Y - else if (Pred == ICmpInst::ICMP_NE && FalseVal == X && + else if (!TrueWhenUnset && FalseVal == X && match(TrueVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C) V = Builder->CreateAnd(X, ~(*Y)); // (X & Y) == 0 ? X ^ Y : X --> X | Y - else if (Pred == ICmpInst::ICMP_EQ && FalseVal == X && + else if (TrueWhenUnset && FalseVal == X && match(TrueVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C) V = Builder->CreateOr(X, *Y); // (X & Y) != 0 ? X : X ^ Y --> X | Y - else if (Pred == ICmpInst::ICMP_NE && TrueVal == X && + else if (!TrueWhenUnset && TrueVal == X && match(FalseVal, m_Xor(m_Specific(X), m_APInt(C))) && *Y == *C) V = Builder->CreateOr(X, *Y); diff --git a/test/Transforms/InstCombine/select.ll b/test/Transforms/InstCombine/select.ll index db3d77aedea..44ec889e53e 100644 --- a/test/Transforms/InstCombine/select.ll +++ b/test/Transforms/InstCombine/select.ll @@ -1050,6 +1050,39 @@ define i64 @select_icmp_x_and_8_ne_0_y_or_8(i32 %x, i64 %y) { ret i64 %or.y } +; CHECK-LABEL: @select_icmp_and_2147483648_ne_0_xor_2147483648( +; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, 2147483647 +; CHECK-NEXT: ret i32 [[AND]] +define i32 @select_icmp_and_2147483648_ne_0_xor_2147483648(i32 %x) { + %and = and i32 %x, 2147483648 + %cmp = icmp eq i32 %and, 0 + %xor = xor i32 %x, 2147483648 + %x.xor = select i1 %cmp, i32 %x, i32 %xor + ret i32 %x.xor +} + +; CHECK-LABEL: @select_icmp_and_2147483648_eq_0_xor_2147483648( +; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 %x, -2147483648 +; CHECK-NEXT: ret i32 [[OR]] +define i32 @select_icmp_and_2147483648_eq_0_xor_2147483648(i32 %x) { + %and = and i32 %x, 2147483648 + %cmp = icmp eq i32 %and, 0 + %xor = xor i32 %x, 2147483648 + %xor.x = select i1 %cmp, i32 %xor, i32 %x + ret i32 %xor.x +} + +; CHECK-LABEL: @select_icmp_x_and_2147483648_ne_0_or_2147483648( +; CHECK: xor i32 %1, -2147483648 +; CHECK: or i32 %2, %x +define i32 @select_icmp_x_and_2147483648_ne_0_or_2147483648(i32 %x) { + %and = and i32 %x, 2147483648 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %x, 2147483648 + %or.x = select i1 %cmp, i32 %or, i32 %x + ret i32 %or.x +} + define i32 @test65(i64 %x) { %1 = and i64 %x, 16 %2 = icmp ne i64 %1, 0