return nullptr;
}
+/// An alternative way to test if a bit is set or not uses sgt/slt instead of
+/// eq/ne.
+static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *TrueVal,
+ Value *FalseVal,
+ bool TrueWhenUnset) {
+ unsigned BitWidth = TrueVal->getType()->getScalarSizeInBits();
+ APInt MinSignedValue;
+ Value *X;
+ if (match(CmpLHS, m_Trunc(m_Value(X))) && (X == TrueVal || X == FalseVal)) {
+ // icmp slt (trunc X), 0 <--> icmp ne (and X, C), 0
+ // icmp sgt (trunc X), -1 <--> icmp eq (and X, C), 0
+ unsigned DestSize = CmpLHS->getType()->getScalarSizeInBits();
+ MinSignedValue = APInt::getSignedMinValue(DestSize).zext(BitWidth);
+ } else {
+ // icmp slt X, 0 <--> icmp ne (and X, C), 0
+ // icmp sgt X, -1 <--> icmp eq (and X, C), 0
+ X = CmpLHS;
+ MinSignedValue = APInt::getSignedMinValue(BitWidth);
+ }
+
+ if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, X, &MinSignedValue,
+ TrueWhenUnset))
+ return V;
+
+ return nullptr;
+}
+
/// Try to simplify a select instruction when its condition operand is an
/// integer comparison.
static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
// FIXME: This code is nearly duplicated in InstCombine. Using/refactoring
// decomposeBitTestICmp() might help.
- unsigned BitWidth =
- Q.DL.getTypeSizeInBits(TrueVal->getType()->getScalarType());
- APInt MinSignedValue = APInt::getSignBit(BitWidth);
if (ICmpInst::isEquality(Pred) && match(CmpRHS, m_Zero())) {
Value *X;
const APInt *Y;
Pred == ICmpInst::ICMP_EQ))
return V;
} else if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, m_Zero())) {
- if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, CmpLHS,
- &MinSignedValue, false))
+ // Comparing signed-less-than 0 checks if the sign bit is set.
+ if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal,
+ false))
return V;
} else if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, m_AllOnes())) {
- if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, CmpLHS,
- &MinSignedValue, true))
+ // Comparing signed-greater-than -1 checks if the sign bit is not set.
+ if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal,
+ true))
return V;
}
define i32 @select_icmp_trunc_8_ne_0_or_128(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_or_128(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TRUNC]], -1
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 %x
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%trunc = trunc i32 %x to i8
%cmp = icmp sgt i8 %trunc, -1
define i32 @select_icmp_trunc_8_ne_0_or_128_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_or_128_alt(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TRUNC]], 0
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[OR]]
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%trunc = trunc i32 %x to i8
%cmp = icmp slt i8 %trunc, 0
define i32 @select_icmp_trunc_8_eq_0_or_128(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_or_128(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TRUNC]], 0
-; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 %x
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 %x
;
%trunc = trunc i32 %x to i8
%cmp = icmp slt i8 %trunc, 0
define i32 @select_icmp_trunc_8_eq_0_or_128_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_or_128_alt(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TRUNC]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[OR]]
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 %x
;
%trunc = trunc i32 %x to i8
%cmp = icmp sgt i8 %trunc, -1
define i32 @select_icmp_trunc_8_eq_0_and_not_8(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_and_not_8(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[TRUNC]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[AND]]
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 [[AND]]
;
%trunc = trunc i32 %x to i4
%cmp = icmp sgt i4 %trunc, -1
define i32 @select_icmp_trunc_8_eq_0_and_not_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_and_not_8_alt(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i4 [[TRUNC]], 0
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 %x
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 [[AND]]
;
%trunc = trunc i32 %x to i4
%cmp = icmp slt i4 %trunc, 0
define i32 @select_icmp_trunc_8_ne_0_and_not_8(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i4 [[TRUNC]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[AND]]
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 %x
;
%trunc = trunc i32 %x to i4
%cmp = icmp slt i4 %trunc, 0
define i32 @select_icmp_trunc_8_ne_0_and_not_8_alt(i32 %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8_alt(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[TRUNC]], -1
-; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 %x
-; CHECK-NEXT: ret i32 [[SEL]]
+; CHECK-NEXT: ret i32 %x
;
%trunc = trunc i32 %x to i4
%cmp = icmp sgt i4 %trunc, -1
define <2 x i32> @select_icmp_trunc_8_ne_0_and_not_8_alt_vec(<2 x i32> %x) {
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8_alt_vec(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc <2 x i32> %x to <2 x i4>
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i4> [[TRUNC]], <i4 -1, i4 -1>
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> %x, <i32 -9, i32 -9>
-; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[AND]], <2 x i32> %x
-; CHECK-NEXT: ret <2 x i32> [[SEL]]
+; CHECK-NEXT: ret <2 x i32> %x
;
%trunc = trunc <2 x i32> %x to <2 x i4>
%cmp = icmp sgt <2 x i4> %trunc, <i4 -1, i4 -1>