diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -1323,8 +1323,14 @@ return new SExtInst(NewSh, Ty); } - // ashr i32 (X -nsw Y), 31 --> sext (X < Y) Value *Y; + + // ashr i32 or(X,-X), 31 --> sext (X != 0) + if (ShAmt == BitWidth - 1 && + match(Op0, m_OneUse(m_c_Or(m_Neg(m_Value(X)), m_Value(Y)))) && X == Y) + return new SExtInst(Builder.CreateICmpNE(X, ConstantInt::get(Ty, 0)), Ty); + + // ashr i32 (X -nsw Y), 31 --> sext (X < Y) if (ShAmt == BitWidth - 1 && match(Op0, m_OneUse(m_NSWSub(m_Value(X), m_Value(Y))))) return new SExtInst(Builder.CreateICmpSLT(X, Y), Ty); diff --git a/llvm/test/Transforms/InstCombine/sub-ashr-or-to-icmp-select.ll b/llvm/test/Transforms/InstCombine/sub-ashr-or-to-icmp-select.ll --- a/llvm/test/Transforms/InstCombine/sub-ashr-or-to-icmp-select.ll +++ b/llvm/test/Transforms/InstCombine/sub-ashr-or-to-icmp-select.ll @@ -72,6 +72,18 @@ ret i64 %or } +define i32 @neg_or_ashr_i32(i32 %x) { +; CHECK-LABEL: @neg_or_ashr_i32( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], 0 +; CHECK-NEXT: [[SHR:%.*]] = sext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[SHR]] +; + %neg = sub i32 0, %x + %or = or i32 %neg, %x + %shr = ashr i32 %or, 31 + ret i32 %shr +} + ; nuw nsw define i32 @sub_ashr_or_i32_nuw_nsw(i32 %x, i32 %y) { @@ -100,6 +112,18 @@ ret i32 %or } +define i32 @neg_or_ashr_i32_commute(i32 %x) { +; CHECK-LABEL: @neg_or_ashr_i32_commute( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], 0 +; CHECK-NEXT: [[SHR:%.*]] = sext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[SHR]] +; + %neg = sub i32 0, %x + %or = or i32 %x, %neg + %shr = ashr i32 %or, 31 + ret i32 %shr +} + ; Vector Types define <4 x i32> @sub_ashr_or_i32_vec(<4 x i32> %x, <4 x i32> %y) { @@ -126,6 +150,18 @@ ret <4 x i32> %or } +define <4 x i32> @neg_or_ashr_i32_vec(<4 x i32> %x) { +; CHECK-LABEL: @neg_or_ashr_i32_vec( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <4 x i32> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[SHR:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i32> +; CHECK-NEXT: ret <4 x i32> [[SHR]] +; + %neg = sub <4 x i32> zeroinitializer, %x + %or = or <4 x i32> %neg, %x + %shr = ashr <4 x i32> %or, + ret <4 x i32> %shr +} + define <4 x i32> @sub_ashr_or_i32_vec_commute(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @sub_ashr_or_i32_vec_commute( ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <4 x i32> [[Y:%.*]], [[X:%.*]] @@ -138,6 +174,18 @@ ret <4 x i32> %or } +define <4 x i32> @neg_or_ashr_i32_vec_commute(<4 x i32> %x) { +; CHECK-LABEL: @neg_or_ashr_i32_vec_commute( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <4 x i32> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[SHR:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i32> +; CHECK-NEXT: ret <4 x i32> [[SHR]] +; + %neg = sub <4 x i32> zeroinitializer, %x + %or = or <4 x i32> %x, %neg + %shr = ashr <4 x i32> %or, + ret <4 x i32> %shr +} + ; Extra uses define i32 @sub_ashr_or_i32_extra_use_sub(i32 %x, i32 %y, i32* %p) { @@ -169,6 +217,21 @@ ret i32 %or } +define i32 @neg_extra_use_or_ashr_i32(i32 %x, i32* %p) { +; CHECK-LABEL: @neg_extra_use_or_ashr_i32( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X]], 0 +; CHECK-NEXT: [[SHR:%.*]] = sext i1 [[TMP1]] to i32 +; CHECK-NEXT: store i32 [[NEG]], i32* [[P:%.*]], align 4 +; CHECK-NEXT: ret i32 [[SHR]] +; + %neg = sub i32 0, %x + %or = or i32 %neg, %x + %shr = ashr i32 %or, 31 + store i32 %neg, i32* %p + ret i32 %shr +} + ; Negative Tests define i32 @sub_ashr_or_i32_extra_use_ashr(i32 %x, i32 %y, i32* %p) { @@ -199,6 +262,21 @@ ret i32 %or } +define i32 @neg_or_extra_use_ashr_i32(i32 %x, i32* %p) { +; CHECK-LABEL: @neg_or_extra_use_ashr_i32( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[OR:%.*]] = or i32 [[NEG]], [[X]] +; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[OR]], 31 +; CHECK-NEXT: store i32 [[OR]], i32* [[P:%.*]], align 4 +; CHECK-NEXT: ret i32 [[SHR]] +; + %neg = sub i32 0, %x + %or = or i32 %neg, %x + %shr = ashr i32 %or, 31 + store i32 %or, i32* %p + ret i32 %shr +} + define <4 x i32> @sub_ashr_or_i32_vec_undef1(<4 x i32> %x) { ; CHECK-LABEL: @sub_ashr_or_i32_vec_undef1( ; CHECK-NEXT: [[SUB:%.*]] = sub <4 x i32> , [[X:%.*]]