diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1566,6 +1566,19 @@ NewRHS |= Known.One & APInt::getHighBitsSet(SrcBits, SrcBits - DstBits); return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), NewRHS)); } + + // Simplify: + // (icmp eq (trunc (1 << Y) to i[N]), 0) --> (icmp ugt Y, N-1) + // (icmp ne (trunc (1 << Y) to i[N]), 0) --> (icmp ult Y, N) + Value *Y; + if (match(X, m_Shl(m_One(), m_Value(Y)))) { + if (Pred == ICmpInst::ICMP_EQ) + return new ICmpInst(ICmpInst::ICMP_UGT, Y, + ConstantInt::get(X->getType(), DstBits - 1)); + else + return new ICmpInst(ICmpInst::ICMP_ULT, Y, + ConstantInt::get(X->getType(), DstBits)); + } } // Look through truncated right-shift of the sign-bit for a sign-bit check: diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc-shl.ll b/llvm/test/Transforms/InstCombine/icmp-trunc-shl.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/icmp-trunc-shl.ll @@ -0,0 +1,332 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +define i1 @eq_i32_to_i16(i32 %a) { +; CHECK-LABEL: @eq_i32_to_i16( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[A:%.*]], 15 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i16 + %r = icmp eq i16 %t, 0 + ret i1 %r +} + +define i1 @eq_i32_to_i8(i32 %a) { +; CHECK-LABEL: @eq_i32_to_i8( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[A:%.*]], 7 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i8 + %r = icmp eq i8 %t, 0 + ret i1 %r +} + +define i1 @eq_i32_to_i4(i32 %a) { +; CHECK-LABEL: @eq_i32_to_i4( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[A:%.*]], 3 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i4 + %r = icmp eq i4 %t, 0 + ret i1 %r +} + +define i1 @eq_i32_to_i2(i32 %a) { +; CHECK-LABEL: @eq_i32_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[A:%.*]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i2 + %r = icmp eq i2 %t, 0 + ret i1 %r +} + +define i1 @eq_i32_to_i1(i32 %a) { +; CHECK-LABEL: @eq_i32_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i1 + %r = icmp eq i1 %t, 0 + ret i1 %r +} + +define i1 @eq_i16_to_i8(i16 %a) { +; CHECK-LABEL: @eq_i16_to_i8( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i16 [[A:%.*]], 7 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i8 + %r = icmp eq i8 %t, 0 + ret i1 %r +} + +define i1 @eq_i16_to_i4(i16 %a) { +; CHECK-LABEL: @eq_i16_to_i4( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i16 [[A:%.*]], 3 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i4 + %r = icmp eq i4 %t, 0 + ret i1 %r +} + +define i1 @eq_i16_to_i2(i16 %a) { +; CHECK-LABEL: @eq_i16_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i16 [[A:%.*]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i2 + %r = icmp eq i2 %t, 0 + ret i1 %r +} + +define i1 @eq_i16_to_i1(i16 %a) { +; CHECK-LABEL: @eq_i16_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i16 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i1 + %r = icmp eq i1 %t, 0 + ret i1 %r +} + +define i1 @eq_i8_to_i4(i8 %a) { +; CHECK-LABEL: @eq_i8_to_i4( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[A:%.*]], 3 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i8 1, %a + %t = trunc i8 %shl to i4 + %r = icmp eq i4 %t, 0 + ret i1 %r +} + +define i1 @eq_i8_to_i2(i8 %a) { +; CHECK-LABEL: @eq_i8_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[A:%.*]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i8 1, %a + %t = trunc i8 %shl to i2 + %r = icmp eq i2 %t, 0 + ret i1 %r +} + +define i1 @eq_i8_to_i1(i8 %a) { +; CHECK-LABEL: @eq_i8_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i8 1, %a + %t = trunc i8 %shl to i1 + %r = icmp eq i1 %t, 0 + ret i1 %r +} + +define i1 @eq_i4_to_i2(i4 %a) { +; CHECK-LABEL: @eq_i4_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ugt i4 [[A:%.*]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i4 1, %a + %t = trunc i4 %shl to i2 + %r = icmp eq i2 %t, 0 + ret i1 %r +} + +define i1 @eq_i4_to_i1(i4 %a) { +; CHECK-LABEL: @eq_i4_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i4 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i4 1, %a + %t = trunc i4 %shl to i1 + %r = icmp eq i1 %t, 0 + ret i1 %r +} + +define i1 @eq_i2_to_i1(i2 %a) { +; CHECK-LABEL: @eq_i2_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i2 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i2 1, %a + %t = trunc i2 %shl to i1 + %r = icmp eq i1 %t, 0 + ret i1 %r +} + +define i1 @ne_i32_to_i16(i32 %a) { +; CHECK-LABEL: @ne_i32_to_i16( +; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[A:%.*]], 16 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i16 + %r = icmp ne i16 %t, 0 + ret i1 %r +} + +define i1 @ne_i32_to_i8(i32 %a) { +; CHECK-LABEL: @ne_i32_to_i8( +; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[A:%.*]], 8 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i8 + %r = icmp ne i8 %t, 0 + ret i1 %r +} + +define i1 @ne_i32_to_i4(i32 %a) { +; CHECK-LABEL: @ne_i32_to_i4( +; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[A:%.*]], 4 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i4 + %r = icmp ne i4 %t, 0 + ret i1 %r +} + +define i1 @ne_i32_to_i2(i32 %a) { +; CHECK-LABEL: @ne_i32_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[A:%.*]], 2 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i2 + %r = icmp ne i2 %t, 0 + ret i1 %r +} + +define i1 @ne_i32_to_i1(i32 %a) { +; CHECK-LABEL: @ne_i32_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i32 1, %a + %t = trunc i32 %shl to i1 + %r = icmp ne i1 %t, 0 + ret i1 %r +} + +define i1 @ne_i16_to_i8(i16 %a) { +; CHECK-LABEL: @ne_i16_to_i8( +; CHECK-NEXT: [[R:%.*]] = icmp ult i16 [[A:%.*]], 8 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i8 + %r = icmp ne i8 %t, 0 + ret i1 %r +} + +define i1 @ne_i16_to_i4(i16 %a) { +; CHECK-LABEL: @ne_i16_to_i4( +; CHECK-NEXT: [[R:%.*]] = icmp ult i16 [[A:%.*]], 4 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i4 + %r = icmp ne i4 %t, 0 + ret i1 %r +} + +define i1 @ne_i16_to_i2(i16 %a) { +; CHECK-LABEL: @ne_i16_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ult i16 [[A:%.*]], 2 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i2 + %r = icmp ne i2 %t, 0 + ret i1 %r +} + +define i1 @ne_i16_to_i1(i16 %a) { +; CHECK-LABEL: @ne_i16_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i16 1, %a + %t = trunc i16 %shl to i1 + %r = icmp ne i1 %t, 0 + ret i1 %r +} + +define i1 @ne_i8_to_i4(i8 %a) { +; CHECK-LABEL: @ne_i8_to_i4( +; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[A:%.*]], 4 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i8 1, %a + %t = trunc i8 %shl to i4 + %r = icmp ne i4 %t, 0 + ret i1 %r +} + +define i1 @ne_i8_to_i2(i8 %a) { +; CHECK-LABEL: @ne_i8_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[A:%.*]], 2 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i8 1, %a + %t = trunc i8 %shl to i2 + %r = icmp ne i2 %t, 0 + ret i1 %r +} + +define i1 @ne_i8_to_i1(i8 %a) { +; CHECK-LABEL: @ne_i8_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i8 1, %a + %t = trunc i8 %shl to i1 + %r = icmp ne i1 %t, 0 + ret i1 %r +} + +define i1 @ne_i4_to_i2(i4 %a) { +; CHECK-LABEL: @ne_i4_to_i2( +; CHECK-NEXT: [[R:%.*]] = icmp ult i4 [[A:%.*]], 2 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i4 1, %a + %t = trunc i4 %shl to i2 + %r = icmp ne i2 %t, 0 + ret i1 %r +} + +define i1 @ne_i4_to_i1(i4 %a) { +; CHECK-LABEL: @ne_i4_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i4 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i4 1, %a + %t = trunc i4 %shl to i1 + %r = icmp ne i1 %t, 0 + ret i1 %r +} + +define i1 @ne_i2_to_i1(i2 %a) { +; CHECK-LABEL: @ne_i2_to_i1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i2 [[A:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %shl = shl i2 1, %a + %t = trunc i2 %shl to i1 + %r = icmp ne i1 %t, 0 + ret i1 %r +}