diff options
Diffstat (limited to 'llvm/test/Transforms/InstSimplify')
89 files changed, 26031 insertions, 0 deletions
diff --git a/llvm/test/Transforms/InstSimplify/2010-12-20-Boolean.ll b/llvm/test/Transforms/InstSimplify/2010-12-20-Boolean.ll new file mode 100644 index 00000000000..33f2176f7c9 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/2010-12-20-Boolean.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i1 @add(i1 %x) { +; CHECK-LABEL: @add( +; CHECK: ret i1 false +; + %z = add i1 %x, %x + ret i1 %z +} + +define i1 @sub(i1 %x) { +; CHECK-LABEL: @sub( +; CHECK: ret i1 %x +; + %z = sub i1 false, %x + ret i1 %z +} + +define i1 @mul(i1 %x) { +; CHECK-LABEL: @mul( +; CHECK: ret i1 %x +; + %z = mul i1 %x, %x + ret i1 %z +} + +define i1 @ne(i1 %x) { +; CHECK-LABEL: @ne( +; CHECK: ret i1 %x +; + %z = icmp ne i1 %x, 0 + ret i1 %z +} diff --git a/llvm/test/Transforms/InstSimplify/2011-01-14-Thread.ll b/llvm/test/Transforms/InstSimplify/2011-01-14-Thread.ll new file mode 100644 index 00000000000..9de06600c0c --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/2011-01-14-Thread.ll @@ -0,0 +1,9 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @shift_select(i1 %cond) { +; CHECK-LABEL: @shift_select( + %s = select i1 %cond, i32 0, i32 1 + %r = lshr i32 %s, 1 + ret i32 %r +; CHECK: ret i32 0 +} diff --git a/llvm/test/Transforms/InstSimplify/2011-02-01-Vector.ll b/llvm/test/Transforms/InstSimplify/2011-02-01-Vector.ll new file mode 100644 index 00000000000..3cbbf350ec1 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/2011-02-01-Vector.ll @@ -0,0 +1,8 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define <2 x i32> @sdiv(<2 x i32> %x) { +; CHECK-LABEL: @sdiv( + %div = sdiv <2 x i32> %x, <i32 1, i32 1> + ret <2 x i32> %div +; CHECK: ret <2 x i32> %x +} diff --git a/llvm/test/Transforms/InstSimplify/2011-09-05-InsertExtractValue.ll b/llvm/test/Transforms/InstSimplify/2011-09-05-InsertExtractValue.ll new file mode 100644 index 00000000000..2c35ed7f390 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/2011-09-05-InsertExtractValue.ll @@ -0,0 +1,55 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +declare void @bar() + +define void @test1() personality i32 (i32, i64, i8*, i8*)* @__gxx_personality_v0 { +entry: + invoke void @bar() to label %cont unwind label %lpad +cont: + ret void +lpad: + %ex = landingpad { i8*, i32 } cleanup + %exc_ptr = extractvalue { i8*, i32 } %ex, 0 + %filter = extractvalue { i8*, i32 } %ex, 1 + %exc_ptr2 = insertvalue { i8*, i32 } undef, i8* %exc_ptr, 0 + %filter2 = insertvalue { i8*, i32 } %exc_ptr2, i32 %filter, 1 + resume { i8*, i32 } %filter2 +; CHECK-LABEL: @test1( +; CHECK-NOT: extractvalue +; CHECK-NOT: insertvalue +} + +declare i32 @__gxx_personality_v0(i32, i64, i8*, i8*) + +define { i8, i32 } @test2({ i8*, i32 } %x) { + %ex = extractvalue { i8*, i32 } %x, 1 + %ins = insertvalue { i8, i32 } undef, i32 %ex, 1 + ret { i8, i32 } %ins +; CHECK-LABEL: @test2( +} + +define i32 @test3(i32 %a, float %b) { + %agg1 = insertvalue {i32, float} undef, i32 %a, 0 + %agg2 = insertvalue {i32, float} %agg1, float %b, 1 + %ev = extractvalue {i32, float} %agg2, 0 + ret i32 %ev +; CHECK-LABEL: @test3( +; CHECK: ret i32 %a +} + +define i8 @test4(<8 x i8> %V) { + %add = add <8 x i8> %V, bitcast (double 0x319BEB8FD172E36 to <8 x i8>) + %extract = extractelement <8 x i8> %add, i32 6 + ret i8 %extract +; CHECK-LABEL: @test4( +; CHECK: %[[add:.*]] = add <8 x i8> %V, bitcast (<1 x double> <double 0x319BEB8FD172E36> to <8 x i8>) +; CHECK-NEXT: %[[extract:.*]] = extractelement <8 x i8> %[[add]], i32 6 +; CHECK-NEXT: ret i8 %[[extract]] +} + +define i32 @test5(<4 x i32> %V) { + %extract = extractelement <4 x i32> %V, i32 undef + ret i32 %extract +} +; CHECK-LABEL: @test5( +; CHECK: ret i32 undef diff --git a/llvm/test/Transforms/InstSimplify/2011-10-27-BinOpCrash.ll b/llvm/test/Transforms/InstSimplify/2011-10-27-BinOpCrash.ll new file mode 100644 index 00000000000..5380a7bb617 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/2011-10-27-BinOpCrash.ll @@ -0,0 +1,12 @@ +; RUN: opt < %s -instcombine + +@_ZN11xercesc_2_5L11gDigitCharsE = external constant [32 x i16], align 2 +@_ZN11xercesc_2_5L10gBaseCharsE = external constant [354 x i16], align 2 +@_ZN11xercesc_2_5L17gIdeographicCharsE = external constant [7 x i16], align 2 +@_ZN11xercesc_2_5L15gCombiningCharsE = external constant [163 x i16], align 2 + +define i32 @_ZN11xercesc_2_515XMLRangeFactory11buildRangesEv(i32 %x) { + %a = add i32 %x, add (i32 add (i32 ashr (i32 add (i32 mul (i32 ptrtoint ([32 x i16]* @_ZN11xercesc_2_5L11gDigitCharsE to i32), i32 -1), i32 ptrtoint (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @_ZN11xercesc_2_5L11gDigitCharsE, i32 0, i32 30) to i32)), i32 1), i32 ashr (i32 add (i32 mul (i32 ptrtoint ([7 x i16]* @_ZN11xercesc_2_5L17gIdeographicCharsE to i32), i32 -1), i32 ptrtoint (i16* getelementptr inbounds ([7 x i16], [7 x i16]* @_ZN11xercesc_2_5L17gIdeographicCharsE, i32 0, i32 4) to i32)), i32 1)), i32 8) + %b = add i32 %a, %x + ret i32 %b +} diff --git a/llvm/test/Transforms/InstSimplify/2011-11-23-MaskedBitsCrash.ll b/llvm/test/Transforms/InstSimplify/2011-11-23-MaskedBitsCrash.ll new file mode 100644 index 00000000000..6166536726a --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/2011-11-23-MaskedBitsCrash.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -instsimplify + +; The mul can be proved to always overflow (turning a negative value +; into a positive one) and thus results in undefined behaviour. At +; the same time we were deducing from the nsw flag that that mul could +; be assumed to have a negative value (since if not it has an undefined +; value, which can be taken to be negative). We were reporting the mul +; as being both positive and negative, firing an assertion! +define i1 @test1(i32 %a) { +entry: + %0 = or i32 %a, 1 + %1 = shl i32 %0, 31 + %2 = mul nsw i32 %1, 4 + %3 = and i32 %2, -4 + %4 = icmp ne i32 %3, 0 + ret i1 %4 +} diff --git a/llvm/test/Transforms/InstSimplify/2013-04-19-ConstantFoldingCrash.ll b/llvm/test/Transforms/InstSimplify/2013-04-19-ConstantFoldingCrash.ll new file mode 100644 index 00000000000..164751784a6 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/2013-04-19-ConstantFoldingCrash.ll @@ -0,0 +1,9 @@ +; RUN: opt < %s -instsimplify + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +; PR15791 +define <2 x i64> @test1() { + %a = and <2 x i64> undef, bitcast (<4 x i32> <i32 undef, i32 undef, i32 undef, i32 2147483647> to <2 x i64>) + ret <2 x i64> %a +} diff --git a/llvm/test/Transforms/InstSimplify/AndOrXor.ll b/llvm/test/Transforms/InstSimplify/AndOrXor.ll new file mode 100644 index 00000000000..8054eb04536 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/AndOrXor.ll @@ -0,0 +1,1134 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i8 @and0(i8 %x) { +; CHECK-LABEL: @and0( +; CHECK-NEXT: ret i8 0 +; + %r = and i8 %x, 0 + ret i8 %r +} + +define <2 x i8> @and0_vec_undef_elt(<2 x i8> %x) { +; CHECK-LABEL: @and0_vec_undef_elt( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %r = and <2 x i8> %x, <i8 undef, i8 0> + ret <2 x i8> %r +} + +; add nsw (xor X, signbit), signbit --> X + +define <2 x i32> @add_nsw_signbit(<2 x i32> %x) { +; CHECK-LABEL: @add_nsw_signbit( +; CHECK-NEXT: ret <2 x i32> [[X:%.*]] +; + %y = xor <2 x i32> %x, <i32 -2147483648, i32 -2147483648> + %z = add nsw <2 x i32> %y, <i32 -2147483648, i32 -2147483648> + ret <2 x i32> %z +} + +; Undef elements in either constant vector are ok. + +define <2 x i32> @add_nsw_signbit_undef(<2 x i32> %x) { +; CHECK-LABEL: @add_nsw_signbit_undef( +; CHECK-NEXT: ret <2 x i32> [[X:%.*]] +; + %y = xor <2 x i32> %x, <i32 undef, i32 -2147483648> + %z = add nsw <2 x i32> %y, <i32 -2147483648, i32 undef> + ret <2 x i32> %z +} + +; add nuw (xor X, signbit), signbit --> X + +define <2 x i5> @add_nuw_signbit(<2 x i5> %x) { +; CHECK-LABEL: @add_nuw_signbit( +; CHECK-NEXT: ret <2 x i5> [[X:%.*]] +; + %y = xor <2 x i5> %x, <i5 -16, i5 -16> + %z = add nuw <2 x i5> %y, <i5 -16, i5 -16> + ret <2 x i5> %z +} + +; Undef elements in either constant vector are ok. + +define <2 x i5> @add_nuw_signbit_undef(<2 x i5> %x) { +; CHECK-LABEL: @add_nuw_signbit_undef( +; CHECK-NEXT: ret <2 x i5> [[X:%.*]] +; + %y = xor <2 x i5> %x, <i5 -16, i5 undef> + %z = add nuw <2 x i5> %y, <i5 undef, i5 -16> + ret <2 x i5> %z +} + +define i64 @pow2(i32 %x) { +; CHECK-LABEL: @pow2( +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[X2:%.*]] = and i32 [[X]], [[NEGX]] +; CHECK-NEXT: [[E:%.*]] = zext i32 [[X2]] to i64 +; CHECK-NEXT: ret i64 [[E]] +; + %negx = sub i32 0, %x + %x2 = and i32 %x, %negx + %e = zext i32 %x2 to i64 + %nege = sub i64 0, %e + %e2 = and i64 %e, %nege + ret i64 %e2 +} + +define i64 @pow2b(i32 %x) { +; CHECK-LABEL: @pow2b( +; CHECK-NEXT: [[SH:%.*]] = shl i32 2, [[X:%.*]] +; CHECK-NEXT: [[E:%.*]] = zext i32 [[SH]] to i64 +; CHECK-NEXT: ret i64 [[E]] +; + %sh = shl i32 2, %x + %e = zext i32 %sh to i64 + %nege = sub i64 0, %e + %e2 = and i64 %e, %nege + ret i64 %e2 +} + +define i1 @and_of_icmps0(i32 %b) { +; CHECK-LABEL: @and_of_icmps0( +; CHECK-NEXT: ret i1 false +; + %1 = add i32 %b, 2 + %2 = icmp ult i32 %1, 4 + %cmp3 = icmp sgt i32 %b, 2 + %cmp = and i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @and_of_icmps0_vec(<2 x i32> %b) { +; CHECK-LABEL: @and_of_icmps0_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %1 = add <2 x i32> %b, <i32 2, i32 2> + %2 = icmp ult <2 x i32> %1, <i32 4, i32 4> + %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2> + %cmp = and <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @and_of_icmps1(i32 %b) { +; CHECK-LABEL: @and_of_icmps1( +; CHECK-NEXT: ret i1 false +; + %1 = add nsw i32 %b, 2 + %2 = icmp slt i32 %1, 4 + %cmp3 = icmp sgt i32 %b, 2 + %cmp = and i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @and_of_icmps1_vec(<2 x i32> %b) { +; CHECK-LABEL: @and_of_icmps1_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %1 = add nsw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp slt <2 x i32> %1, <i32 4, i32 4> + %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2> + %cmp = and <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @and_of_icmps2(i32 %b) { +; CHECK-LABEL: @and_of_icmps2( +; CHECK-NEXT: ret i1 false +; + %1 = add i32 %b, 2 + %2 = icmp ule i32 %1, 3 + %cmp3 = icmp sgt i32 %b, 2 + %cmp = and i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @and_of_icmps2_vec(<2 x i32> %b) { +; CHECK-LABEL: @and_of_icmps2_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %1 = add <2 x i32> %b, <i32 2, i32 2> + %2 = icmp ule <2 x i32> %1, <i32 3, i32 3> + %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2> + %cmp = and <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @and_of_icmps3(i32 %b) { +; CHECK-LABEL: @and_of_icmps3( +; CHECK-NEXT: ret i1 false +; + %1 = add nsw i32 %b, 2 + %2 = icmp sle i32 %1, 3 + %cmp3 = icmp sgt i32 %b, 2 + %cmp = and i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @and_of_icmps3_vec(<2 x i32> %b) { +; CHECK-LABEL: @and_of_icmps3_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %1 = add nsw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp sle <2 x i32> %1, <i32 3, i32 3> + %cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2> + %cmp = and <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @and_of_icmps4(i32 %b) { +; CHECK-LABEL: @and_of_icmps4( +; CHECK-NEXT: ret i1 false +; + %1 = add nuw i32 %b, 2 + %2 = icmp ult i32 %1, 4 + %cmp3 = icmp ugt i32 %b, 2 + %cmp = and i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @and_of_icmps4_vec(<2 x i32> %b) { +; CHECK-LABEL: @and_of_icmps4_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %1 = add nuw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp ult <2 x i32> %1, <i32 4, i32 4> + %cmp3 = icmp ugt <2 x i32> %b, <i32 2, i32 2> + %cmp = and <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @and_of_icmps5(i32 %b) { +; CHECK-LABEL: @and_of_icmps5( +; CHECK-NEXT: ret i1 false +; + %1 = add nuw i32 %b, 2 + %2 = icmp ule i32 %1, 3 + %cmp3 = icmp ugt i32 %b, 2 + %cmp = and i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @and_of_icmps5_vec(<2 x i32> %b) { +; CHECK-LABEL: @and_of_icmps5_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %1 = add nuw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp ule <2 x i32> %1, <i32 3, i32 3> + %cmp3 = icmp ugt <2 x i32> %b, <i32 2, i32 2> + %cmp = and <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @or_of_icmps0(i32 %b) { +; CHECK-LABEL: @or_of_icmps0( +; CHECK-NEXT: ret i1 true +; + %1 = add i32 %b, 2 + %2 = icmp uge i32 %1, 4 + %cmp3 = icmp sle i32 %b, 2 + %cmp = or i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @or_of_icmps0_vec(<2 x i32> %b) { +; CHECK-LABEL: @or_of_icmps0_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %1 = add <2 x i32> %b, <i32 2, i32 2> + %2 = icmp uge <2 x i32> %1, <i32 4, i32 4> + %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2> + %cmp = or <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @or_of_icmps1(i32 %b) { +; CHECK-LABEL: @or_of_icmps1( +; CHECK-NEXT: ret i1 true +; + %1 = add nsw i32 %b, 2 + %2 = icmp sge i32 %1, 4 + %cmp3 = icmp sle i32 %b, 2 + %cmp = or i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @or_of_icmps1_vec(<2 x i32> %b) { +; CHECK-LABEL: @or_of_icmps1_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %1 = add nsw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp sge <2 x i32> %1, <i32 4, i32 4> + %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2> + %cmp = or <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @or_of_icmps2(i32 %b) { +; CHECK-LABEL: @or_of_icmps2( +; CHECK-NEXT: ret i1 true +; + %1 = add i32 %b, 2 + %2 = icmp ugt i32 %1, 3 + %cmp3 = icmp sle i32 %b, 2 + %cmp = or i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @or_of_icmps2_vec(<2 x i32> %b) { +; CHECK-LABEL: @or_of_icmps2_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %1 = add <2 x i32> %b, <i32 2, i32 2> + %2 = icmp ugt <2 x i32> %1, <i32 3, i32 3> + %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2> + %cmp = or <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @or_of_icmps3(i32 %b) { +; CHECK-LABEL: @or_of_icmps3( +; CHECK-NEXT: ret i1 true +; + %1 = add nsw i32 %b, 2 + %2 = icmp sgt i32 %1, 3 + %cmp3 = icmp sle i32 %b, 2 + %cmp = or i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @or_of_icmps3_vec(<2 x i32> %b) { +; CHECK-LABEL: @or_of_icmps3_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %1 = add nsw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp sgt <2 x i32> %1, <i32 3, i32 3> + %cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2> + %cmp = or <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @or_of_icmps4(i32 %b) { +; CHECK-LABEL: @or_of_icmps4( +; CHECK-NEXT: ret i1 true +; + %1 = add nuw i32 %b, 2 + %2 = icmp uge i32 %1, 4 + %cmp3 = icmp ule i32 %b, 2 + %cmp = or i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @or_of_icmps4_vec(<2 x i32> %b) { +; CHECK-LABEL: @or_of_icmps4_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %1 = add nuw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp uge <2 x i32> %1, <i32 4, i32 4> + %cmp3 = icmp ule <2 x i32> %b, <i32 2, i32 2> + %cmp = or <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i1 @or_of_icmps5(i32 %b) { +; CHECK-LABEL: @or_of_icmps5( +; CHECK-NEXT: ret i1 true +; + %1 = add nuw i32 %b, 2 + %2 = icmp ugt i32 %1, 3 + %cmp3 = icmp ule i32 %b, 2 + %cmp = or i1 %2, %cmp3 + ret i1 %cmp +} + +define <2 x i1> @or_of_icmps5_vec(<2 x i32> %b) { +; CHECK-LABEL: @or_of_icmps5_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %1 = add nuw <2 x i32> %b, <i32 2, i32 2> + %2 = icmp ugt <2 x i32> %1, <i32 3, i32 3> + %cmp3 = icmp ule <2 x i32> %b, <i32 2, i32 2> + %cmp = or <2 x i1> %2, %cmp3 + ret <2 x i1> %cmp +} + +define i32 @neg_nuw(i32 %x) { +; CHECK-LABEL: @neg_nuw( +; CHECK-NEXT: ret i32 0 +; + %neg = sub nuw i32 0, %x + ret i32 %neg +} + +define i1 @and_icmp1(i32 %x, i32 %y) { +; CHECK-LABEL: @and_icmp1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] +; + %1 = icmp ult i32 %x, %y + %2 = icmp ne i32 %y, 0 + %3 = and i1 %1, %2 + ret i1 %3 +} + +define i1 @and_icmp2(i32 %x, i32 %y) { +; CHECK-LABEL: @and_icmp2( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] +; + %1 = icmp ugt i32 %x, %y + %2 = icmp ne i32 %x, 0 + %3 = and i1 %1, %2 + ret i1 %3 +} + +define i1 @and_icmp3(i32 %x, i32 %y) { +; CHECK-LABEL: @and_icmp3( +; CHECK-NEXT: ret i1 false +; + %1 = icmp ult i32 %x, %y + %2 = icmp eq i32 %y, 0 + %3 = and i1 %1, %2 + ret i1 %3 +} + +define i1 @and_icmp4(i32 %x, i32 %y) { +; CHECK-LABEL: @and_icmp4( +; CHECK-NEXT: ret i1 false +; + %1 = icmp ugt i32 %x, %y + %2 = icmp eq i32 %x, 0 + %3 = and i1 %1, %2 + ret i1 %3 +} + +define i1 @or_icmp1(i32 %x, i32 %y) { +; CHECK-LABEL: @or_icmp1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[Y:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %1 = icmp ult i32 %x, %y + %2 = icmp ne i32 %y, 0 + %3 = or i1 %1, %2 + ret i1 %3 +} + +define i1 @or_icmp2(i32 %x, i32 %y) { +; CHECK-LABEL: @or_icmp2( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %1 = icmp ugt i32 %x, %y + %2 = icmp ne i32 %x, 0 + %3 = or i1 %1, %2 + ret i1 %3 +} + +define i1 @or_icmp3(i32 %x, i32 %y) { +; CHECK-LABEL: @or_icmp3( +; CHECK-NEXT: ret i1 true +; + %1 = icmp uge i32 %x, %y + %2 = icmp ne i32 %y, 0 + %3 = or i1 %1, %2 + ret i1 %3 +} + +define i1 @or_icmp4(i32 %x, i32 %y) { +; CHECK-LABEL: @or_icmp4( +; CHECK-NEXT: ret i1 true +; + %1 = icmp ule i32 %x, %y + %2 = icmp ne i32 %x, 0 + %3 = or i1 %1, %2 + ret i1 %3 +} + +define i1 @or_icmp5(i32 %x, i32 %y) { +; CHECK-LABEL: @or_icmp5( +; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] +; + %1 = icmp uge i32 %x, %y + %2 = icmp eq i32 %y, 0 + %3 = or i1 %1, %2 + ret i1 %3 +} + +define i1 @or_icmp6(i32 %x, i32 %y) { +; CHECK-LABEL: @or_icmp6( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] +; + %1 = icmp ule i32 %x, %y + %2 = icmp eq i32 %x, 0 + %3 = or i1 %1, %2 + ret i1 %3 +} + +; PR27869 - Look through casts to eliminate cmps and bitwise logic. + +define i32 @and_of_zexted_icmps(i32 %i) { +; CHECK-LABEL: @and_of_zexted_icmps( +; CHECK-NEXT: ret i32 0 +; + %cmp0 = icmp eq i32 %i, 0 + %conv0 = zext i1 %cmp0 to i32 + %cmp1 = icmp ugt i32 %i, 4 + %conv1 = zext i1 %cmp1 to i32 + %and = and i32 %conv0, %conv1 + ret i32 %and +} + +; Make sure vectors work too. + +define <4 x i32> @and_of_zexted_icmps_vec(<4 x i32> %i) { +; CHECK-LABEL: @and_of_zexted_icmps_vec( +; CHECK-NEXT: ret <4 x i32> zeroinitializer +; + %cmp0 = icmp eq <4 x i32> %i, zeroinitializer + %conv0 = zext <4 x i1> %cmp0 to <4 x i32> + %cmp1 = icmp slt <4 x i32> %i, zeroinitializer + %conv1 = zext <4 x i1> %cmp1 to <4 x i32> + %and = and <4 x i32> %conv0, %conv1 + ret <4 x i32> %and +} + +; Try a different cast and weird types. + +define i5 @and_of_sexted_icmps(i3 %i) { +; CHECK-LABEL: @and_of_sexted_icmps( +; CHECK-NEXT: ret i5 0 +; + %cmp0 = icmp eq i3 %i, 0 + %conv0 = sext i1 %cmp0 to i5 + %cmp1 = icmp ugt i3 %i, 1 + %conv1 = sext i1 %cmp1 to i5 + %and = and i5 %conv0, %conv1 + ret i5 %and +} + +; Try a different cast and weird vector types. + +define i3 @and_of_bitcast_icmps_vec(<3 x i65> %i) { +; CHECK-LABEL: @and_of_bitcast_icmps_vec( +; CHECK-NEXT: ret i3 0 +; + %cmp0 = icmp sgt <3 x i65> %i, zeroinitializer + %conv0 = bitcast <3 x i1> %cmp0 to i3 + %cmp1 = icmp slt <3 x i65> %i, zeroinitializer + %conv1 = bitcast <3 x i1> %cmp1 to i3 + %and = and i3 %conv0, %conv1 + ret i3 %and +} + +; We can't do this if the casts are different. + +define i16 @and_of_different_cast_icmps(i8 %i) { +; CHECK-LABEL: @and_of_different_cast_icmps( +; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i8 [[I:%.*]], 0 +; CHECK-NEXT: [[CONV0:%.*]] = zext i1 [[CMP0]] to i16 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[I]], 1 +; CHECK-NEXT: [[CONV1:%.*]] = sext i1 [[CMP1]] to i16 +; CHECK-NEXT: [[AND:%.*]] = and i16 [[CONV0]], [[CONV1]] +; CHECK-NEXT: ret i16 [[AND]] +; + %cmp0 = icmp eq i8 %i, 0 + %conv0 = zext i1 %cmp0 to i16 + %cmp1 = icmp eq i8 %i, 1 + %conv1 = sext i1 %cmp1 to i16 + %and = and i16 %conv0, %conv1 + ret i16 %and +} + +define <2 x i3> @and_of_different_cast_icmps_vec(<2 x i8> %i, <2 x i16> %j) { +; CHECK-LABEL: @and_of_different_cast_icmps_vec( +; CHECK-NEXT: [[CMP0:%.*]] = icmp eq <2 x i8> [[I:%.*]], zeroinitializer +; CHECK-NEXT: [[CONV0:%.*]] = zext <2 x i1> [[CMP0]] to <2 x i3> +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i16> [[J:%.*]], <i16 1, i16 1> +; CHECK-NEXT: [[CONV1:%.*]] = zext <2 x i1> [[CMP1]] to <2 x i3> +; CHECK-NEXT: [[AND:%.*]] = and <2 x i3> [[CONV0]], [[CONV1]] +; CHECK-NEXT: ret <2 x i3> [[AND]] +; + %cmp0 = icmp eq <2 x i8> %i, zeroinitializer + %conv0 = zext <2 x i1> %cmp0 to <2 x i3> + %cmp1 = icmp ugt <2 x i16> %j, <i16 1, i16 1> + %conv1 = zext <2 x i1> %cmp1 to <2 x i3> + %and = and <2 x i3> %conv0, %conv1 + ret <2 x i3> %and +} + +define i32 @or_of_zexted_icmps(i32 %i) { +; CHECK-LABEL: @or_of_zexted_icmps( +; CHECK-NEXT: ret i32 1 +; + %cmp0 = icmp ne i32 %i, 0 + %conv0 = zext i1 %cmp0 to i32 + %cmp1 = icmp uge i32 4, %i + %conv1 = zext i1 %cmp1 to i32 + %or = or i32 %conv0, %conv1 + ret i32 %or +} + +; Try a different cast and weird vector types. + +define i3 @or_of_bitcast_icmps_vec(<3 x i65> %i) { +; CHECK-LABEL: @or_of_bitcast_icmps_vec( +; CHECK-NEXT: ret i3 bitcast (<3 x i1> <i1 true, i1 true, i1 true> to i3) +; + %cmp0 = icmp sge <3 x i65> %i, zeroinitializer + %conv0 = bitcast <3 x i1> %cmp0 to i3 + %cmp1 = icmp slt <3 x i65> %i, zeroinitializer + %conv1 = bitcast <3 x i1> %cmp1 to i3 + %or = or i3 %conv0, %conv1 + ret i3 %or +} + +; We can't simplify if the casts are different. + +define i16 @or_of_different_cast_icmps(i8 %i) { +; CHECK-LABEL: @or_of_different_cast_icmps( +; CHECK-NEXT: [[CMP0:%.*]] = icmp ne i8 [[I:%.*]], 0 +; CHECK-NEXT: [[CONV0:%.*]] = zext i1 [[CMP0]] to i16 +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[I]], 1 +; CHECK-NEXT: [[CONV1:%.*]] = sext i1 [[CMP1]] to i16 +; CHECK-NEXT: [[OR:%.*]] = or i16 [[CONV0]], [[CONV1]] +; CHECK-NEXT: ret i16 [[OR]] +; + %cmp0 = icmp ne i8 %i, 0 + %conv0 = zext i1 %cmp0 to i16 + %cmp1 = icmp ne i8 %i, 1 + %conv1 = sext i1 %cmp1 to i16 + %or = or i16 %conv0, %conv1 + ret i16 %or +} + +; (A & ~B) | (A ^ B) -> A ^ B + +define i32 @test43(i32 %a, i32 %b) { +; CHECK-LABEL: @test43( +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %neg = xor i32 %b, -1 + %and = and i32 %a, %neg + %xor = xor i32 %a, %b + %or = or i32 %and, %xor + ret i32 %or +} + +define i32 @test43_commuted_and(i32 %a, i32 %b) { +; CHECK-LABEL: @test43_commuted_and( +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %neg = xor i32 %b, -1 + %and = and i32 %neg, %a + %xor = xor i32 %a, %b + %or = or i32 %and, %xor + ret i32 %or +} + +; Commute operands of the 'or'. +; (A ^ B) | (A & ~B) -> A ^ B + +define i32 @test44(i32 %a, i32 %b) { +; CHECK-LABEL: @test44( +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %xor = xor i32 %a, %b + %neg = xor i32 %b, -1 + %and = and i32 %a, %neg + %or = or i32 %xor, %and + ret i32 %or +} + +define i32 @test44_commuted_and(i32 %a, i32 %b) { +; CHECK-LABEL: @test44_commuted_and( +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %xor = xor i32 %a, %b + %neg = xor i32 %b, -1 + %and = and i32 %neg, %a + %or = or i32 %xor, %and + ret i32 %or +} + +; (~A & ~B) | (~A ^ B) -> ~A ^ B + +define i32 @test45(i32 %a, i32 %b) { +; CHECK-LABEL: @test45( +; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %negb = xor i32 %b, -1 + %and = and i32 %nega, %negb + %xor = xor i32 %a, %negb + %or = or i32 %and, %xor + ret i32 %or +} + +define i32 @test45_commuted_and(i32 %a, i32 %b) { +; CHECK-LABEL: @test45_commuted_and( +; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %negb = xor i32 %b, -1 + %and = and i32 %negb, %nega + %xor = xor i32 %a, %negb + %or = or i32 %and, %xor + ret i32 %or +} + +; Commute operands of the 'or'. +; (~A ^ B) | (~A & ~B) -> ~A ^ B + +define i32 @test46(i32 %a, i32 %b) { +; CHECK-LABEL: @test46( +; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %negb = xor i32 %b, -1 + %and = and i32 %nega, %negb + %xor = xor i32 %a, %negb + %or = or i32 %xor, %and + ret i32 %or +} + +; (~A & ~B) | (~A ^ B) -> ~A ^ B + +define i32 @test46_commuted_and(i32 %a, i32 %b) { +; CHECK-LABEL: @test46_commuted_and( +; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %negb = xor i32 %b, -1 + %and = and i32 %negb, %nega + %xor = xor i32 %a, %negb + %or = or i32 %xor, %and + ret i32 %or +} + +; (~A ^ B) | (A & B) -> ~A ^ B + +define i32 @test47(i32 %a, i32 %b) { +; CHECK-LABEL: @test47( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %a, %b + %xor = xor i32 %nega, %b + %or = or i32 %xor, %and + ret i32 %or +} + +define i32 @test48(i32 %a, i32 %b) { +; CHECK-LABEL: @test48( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %a, %b + %xor = xor i32 %b, %nega + %or = or i32 %xor, %and + ret i32 %or +} + +define i32 @test49(i32 %a, i32 %b) { +; CHECK-LABEL: @test49( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %b, %a + %xor = xor i32 %b, %nega + %or = or i32 %xor, %and + ret i32 %or +} + +define i32 @test50(i32 %a, i32 %b) { +; CHECK-LABEL: @test50( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %b, %a + %xor = xor i32 %nega, %b + %or = or i32 %xor, %and + ret i32 %or +} + +define i32 @test51(i32 %a, i32 %b) { +; CHECK-LABEL: @test51( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %a, %b + %xor = xor i32 %nega, %b + %or = or i32 %and, %xor + ret i32 %or +} + +define i32 @test52(i32 %a, i32 %b) { +; CHECK-LABEL: @test52( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %a, %b + %xor = xor i32 %b, %nega + %or = or i32 %and, %xor + ret i32 %or +} + +define i32 @test53(i32 %a, i32 %b) { +; CHECK-LABEL: @test53( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %b, %a + %xor = xor i32 %b, %nega + %or = or i32 %and, %xor + ret i32 %or +} + +define i32 @test54(i32 %a, i32 %b) { +; CHECK-LABEL: @test54( +; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]] +; CHECK-NEXT: ret i32 [[XOR]] +; + %nega = xor i32 %a, -1 + %and = and i32 %b, %a + %xor = xor i32 %nega, %b + %or = or i32 %and, %xor + ret i32 %or +} + +; (A & B) | ~(A ^ B) -> ~(A ^ B) + +define i32 @test55(i32 %a, i32 %b) { +; CHECK-LABEL: @test55( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]] +; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND]], [[XNOR]] +; CHECK-NEXT: ret i32 [[OR]] +; + %and = and i32 %a, %b + %xor = xor i32 %a, %b + %xnor = xor i32 %xor, -1 + %or = or i32 %and, %xnor + ret i32 %or +} + +; ~(A ^ B) | (A & B) -> ~(A ^ B) + +define i32 @test56(i32 %a, i32 %b) { +; CHECK-LABEL: @test56( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]] +; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[XNOR]], [[AND]] +; CHECK-NEXT: ret i32 [[OR]] +; + %and = and i32 %a, %b + %xor = xor i32 %a, %b + %xnor = xor i32 %xor, -1 + %or = or i32 %xnor, %and + ret i32 %or +} + +; (B & A) | ~(A ^ B) -> ~(A ^ B) + +define i32 @test57(i32 %a, i32 %b) { +; CHECK-LABEL: @test57( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]] +; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND]], [[XNOR]] +; CHECK-NEXT: ret i32 [[OR]] +; + %and = and i32 %b, %a + %xor = xor i32 %a, %b + %xnor = xor i32 %xor, -1 + %or = or i32 %and, %xnor + ret i32 %or +} + +; ~(A ^ B) | (A & B) -> ~(A ^ B) + +define i32 @test58(i32 %a, i32 %b) { +; CHECK-LABEL: @test58( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]] +; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[XNOR]], [[AND]] +; CHECK-NEXT: ret i32 [[OR]] +; + %and = and i32 %b, %a + %xor = xor i32 %a, %b + %xnor = xor i32 %xor, -1 + %or = or i32 %xnor, %and + ret i32 %or +} + +define i8 @lshr_perfect_mask(i8 %x) { +; CHECK-LABEL: @lshr_perfect_mask( +; CHECK-NEXT: [[SH:%.*]] = lshr i8 [[X:%.*]], 5 +; CHECK-NEXT: ret i8 [[SH]] +; + %sh = lshr i8 %x, 5 + %mask = and i8 %sh, 7 ; 0x07 + ret i8 %mask +} + +define <2 x i8> @lshr_oversized_mask_splat(<2 x i8> %x) { +; CHECK-LABEL: @lshr_oversized_mask_splat( +; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 5, i8 5> +; CHECK-NEXT: ret <2 x i8> [[SH]] +; + %sh = lshr <2 x i8> %x, <i8 5, i8 5> + %mask = and <2 x i8> %sh, <i8 135, i8 135> ; 0x87 + ret <2 x i8> %mask +} + +define i8 @lshr_undersized_mask(i8 %x) { +; CHECK-LABEL: @lshr_undersized_mask( +; CHECK-NEXT: [[SH:%.*]] = lshr i8 [[X:%.*]], 5 +; CHECK-NEXT: [[MASK:%.*]] = and i8 [[SH]], -2 +; CHECK-NEXT: ret i8 [[MASK]] +; + %sh = lshr i8 %x, 5 + %mask = and i8 %sh, -2 ; 0xFE + ret i8 %mask +} + +define <2 x i8> @shl_perfect_mask_splat(<2 x i8> %x) { +; CHECK-LABEL: @shl_perfect_mask_splat( +; CHECK-NEXT: [[SH:%.*]] = shl <2 x i8> [[X:%.*]], <i8 6, i8 6> +; CHECK-NEXT: ret <2 x i8> [[SH]] +; + %sh = shl <2 x i8> %x, <i8 6, i8 6> + %mask = and <2 x i8> %sh, <i8 192, i8 192> ; 0xC0 + ret <2 x i8> %mask +} + +define i8 @shl_oversized_mask(i8 %x) { +; CHECK-LABEL: @shl_oversized_mask( +; CHECK-NEXT: [[SH:%.*]] = shl i8 [[X:%.*]], 6 +; CHECK-NEXT: ret i8 [[SH]] +; + %sh = shl i8 %x, 6 + %mask = and i8 %sh, 195 ; 0xC3 + ret i8 %mask +} + +define <2 x i8> @shl_undersized_mask_splat(<2 x i8> %x) { +; CHECK-LABEL: @shl_undersized_mask_splat( +; CHECK-NEXT: [[SH:%.*]] = shl <2 x i8> [[X:%.*]], <i8 6, i8 6> +; CHECK-NEXT: [[MASK:%.*]] = and <2 x i8> [[SH]], <i8 -120, i8 -120> +; CHECK-NEXT: ret <2 x i8> [[MASK]] +; + %sh = shl <2 x i8> %x, <i8 6, i8 6> + %mask = and <2 x i8> %sh, <i8 136, i8 136> ; 0x88 + ret <2 x i8> %mask +} + +define i32 @reversed_not(i32 %a) { +; CHECK-LABEL: @reversed_not( +; CHECK-NEXT: ret i32 -1 +; + %nega = xor i32 -1, %a + %or = or i32 %a, %nega + ret i32 %or +} + +define i64 @shl_or_and1(i32 %a, i1 %b) { +; CHECK-LABEL: @shl_or_and1( +; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[B:%.*]] to i64 +; CHECK-NEXT: ret i64 [[TMP2]] +; + %tmp1 = zext i32 %a to i64 + %tmp2 = zext i1 %b to i64 + %tmp3 = shl nuw i64 %tmp1, 32 + %tmp4 = or i64 %tmp2, %tmp3 + %tmp5 = and i64 %tmp4, 1 + ret i64 %tmp5 +} + +define i64 @shl_or_and2(i32 %a, i1 %b) { +; CHECK-LABEL: @shl_or_and2( +; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[B:%.*]] to i64 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw i64 [[TMP1]], 32 +; CHECK-NEXT: ret i64 [[TMP3]] +; + %tmp1 = zext i1 %b to i64 + %tmp2 = zext i32 %a to i64 + %tmp3 = shl nuw i64 %tmp1, 32 + %tmp4 = or i64 %tmp2, %tmp3 + %tmp5 = and i64 %tmp4, 4294967296 + ret i64 %tmp5 +} + +; concatenate two 32-bit integers and extract lower 32-bit +define i64 @shl_or_and3(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_or_and3( +; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[B:%.*]] to i64 +; CHECK-NEXT: ret i64 [[TMP2]] +; + %tmp1 = zext i32 %a to i64 + %tmp2 = zext i32 %b to i64 + %tmp3 = shl nuw i64 %tmp1, 32 + %tmp4 = or i64 %tmp2, %tmp3 + %tmp5 = and i64 %tmp4, 4294967295 + ret i64 %tmp5 +} + +; concatenate two 16-bit integers and extract higher 16-bit +define i32 @shl_or_and4(i16 %a, i16 %b) { +; CHECK-LABEL: @shl_or_and4( +; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16 +; CHECK-NEXT: ret i32 [[TMP3]] +; + %tmp1 = zext i16 %a to i32 + %tmp2 = zext i16 %b to i32 + %tmp3 = shl nuw i32 %tmp1, 16 + %tmp4 = or i32 %tmp2, %tmp3 + %tmp5 = and i32 %tmp4, 4294901760 ; mask with 0xFFFF0000 + ret i32 %tmp5 +} + +define i128 @shl_or_and5(i64 %a, i1 %b) { +; CHECK-LABEL: @shl_or_and5( +; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[B:%.*]] to i128 +; CHECK-NEXT: ret i128 [[TMP2]] +; + %tmp1 = zext i64 %a to i128 + %tmp2 = zext i1 %b to i128 + %tmp3 = shl nuw i128 %tmp1, 64 + %tmp4 = or i128 %tmp2, %tmp3 + %tmp5 = and i128 %tmp4, 1 + ret i128 %tmp5 +} + +; A variation of above test cases; it fails due to the mask value +define i32 @shl_or_and6(i16 %a, i16 %b) { +; CHECK-LABEL: @shl_or_and6( +; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[B:%.*]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], -65535 +; CHECK-NEXT: ret i32 [[TMP5]] +; + %tmp1 = zext i16 %a to i32 + %tmp2 = zext i16 %b to i32 + %tmp3 = shl nuw i32 %tmp1, 16 + %tmp4 = or i32 %tmp2, %tmp3 + %tmp5 = and i32 %tmp4, 4294901761 ; mask with 0xFFFF0001 + ret i32 %tmp5 +} + +; A variation of above test cases; it fails due to the mask value +define i32 @shl_or_and7(i16 %a, i16 %b) { +; CHECK-LABEL: @shl_or_and7( +; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[B:%.*]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], -131072 +; CHECK-NEXT: ret i32 [[TMP5]] +; + %tmp1 = zext i16 %a to i32 + %tmp2 = zext i16 %b to i32 + %tmp3 = shl nuw i32 %tmp1, 16 + %tmp4 = or i32 %tmp2, %tmp3 + %tmp5 = and i32 %tmp4, 4294836224 ; mask with 0xFFFE0000 + ret i32 %tmp5 +} + +; A variation of above test cases; it fails due to the mask value +define i32 @shl_or_and8(i16 %a, i16 %b) { +; CHECK-LABEL: @shl_or_and8( +; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[B:%.*]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw i32 [[TMP1]], 16 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 131071 +; CHECK-NEXT: ret i32 [[TMP5]] +; + %tmp1 = zext i16 %a to i32 + %tmp2 = zext i16 %b to i32 + %tmp3 = shl nuw i32 %tmp1, 16 + %tmp4 = or i32 %tmp2, %tmp3 + %tmp5 = and i32 %tmp4, 131071 ; mask with 0x1FFFF + ret i32 %tmp5 +} + +define <2 x i64> @shl_or_and1v(<2 x i32> %a, <2 x i1> %b) { +; CHECK-LABEL: @shl_or_and1v( +; CHECK-NEXT: [[TMP2:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i64> +; CHECK-NEXT: ret <2 x i64> [[TMP2]] +; + %tmp1 = zext <2 x i32> %a to <2 x i64> + %tmp2 = zext <2 x i1> %b to <2 x i64> + %tmp3 = shl nuw <2 x i64> %tmp1, <i64 32, i64 32> + %tmp4 = or <2 x i64> %tmp3, %tmp2 + %tmp5 = and <2 x i64> %tmp4, <i64 1, i64 1> + ret <2 x i64> %tmp5 +} + +define <2 x i64> @shl_or_and2v(<2 x i32> %a, <2 x i1> %b) { +; CHECK-LABEL: @shl_or_and2v( +; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i64> +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw <2 x i64> [[TMP1]], <i64 32, i64 32> +; CHECK-NEXT: ret <2 x i64> [[TMP3]] +; + %tmp1 = zext <2 x i1> %b to <2 x i64> + %tmp2 = zext <2 x i32> %a to <2 x i64> + %tmp3 = shl nuw <2 x i64> %tmp1, <i64 32, i64 32> + %tmp4 = or <2 x i64> %tmp2, %tmp3 + %tmp5 = and <2 x i64> %tmp4, <i64 4294967296, i64 4294967296> + ret <2 x i64> %tmp5 +} + +define <2 x i32> @shl_or_and3v(<2 x i16> %a, <2 x i16> %b) { +; A variation of above test case, but fails due to the mask value +; CHECK-LABEL: @shl_or_and3v( +; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i16> [[A:%.*]] to <2 x i32> +; CHECK-NEXT: [[TMP2:%.*]] = zext <2 x i16> [[B:%.*]] to <2 x i32> +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw <2 x i32> [[TMP1]], <i32 16, i32 16> +; CHECK-NEXT: [[TMP4:%.*]] = or <2 x i32> [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = and <2 x i32> [[TMP4]], <i32 -65535, i32 -65535> +; CHECK-NEXT: ret <2 x i32> [[TMP5]] +; + %tmp1 = zext <2 x i16> %a to <2 x i32> + %tmp2 = zext <2 x i16> %b to <2 x i32> + %tmp3 = shl nuw <2 x i32> %tmp1, <i32 16, i32 16> + %tmp4 = or <2 x i32> %tmp2, %tmp3 + %tmp5 = and <2 x i32> %tmp4, <i32 4294901761, i32 4294901761> ; mask with 0xFFFF0001 + ret <2 x i32> %tmp5 +} diff --git a/llvm/test/Transforms/InstSimplify/add-mask.ll b/llvm/test/Transforms/InstSimplify/add-mask.ll new file mode 100644 index 00000000000..e30a35f5312 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/add-mask.ll @@ -0,0 +1,79 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt -S -instsimplify < %s | FileCheck %s + +define i1 @test(i32 %a) { +; CHECK-LABEL: @test( +; CHECK: ret i1 false +; + %rhs = add i32 %a, -1 + %and = and i32 %a, %rhs + %res = icmp eq i32 %and, 1 + ret i1 %res +} + +define i1 @test2(i32 %a) { +; CHECK-LABEL: @test2( +; CHECK: ret i1 false +; + %rhs = add i32 %a, 1 + %and = and i32 %a, %rhs + %res = icmp eq i32 %and, 1 + ret i1 %res +} + +define i1 @test3(i32 %a) { +; CHECK-LABEL: @test3( +; CHECK: ret i1 false +; + %rhs = add i32 %a, 7 + %and = and i32 %a, %rhs + %res = icmp eq i32 %and, 1 + ret i1 %res +} + +@B = external global i32 +declare void @llvm.assume(i1) + +; Known bits without a constant +define i1 @test4(i32 %a) { +; CHECK-LABEL: @test4( +; CHECK: [[B:%.*]] = load i32, i32* @B +; CHECK-NEXT: [[B_AND:%.*]] = and i32 [[B]], 1 +; CHECK-NEXT: [[B_CND:%.*]] = icmp eq i32 [[B_AND]], 1 +; CHECK-NEXT: call void @llvm.assume(i1 [[B_CND]]) +; CHECK-NEXT: ret i1 false +; + %b = load i32, i32* @B + %b.and = and i32 %b, 1 + %b.cnd = icmp eq i32 %b.and, 1 + call void @llvm.assume(i1 %b.cnd) + + %rhs = add i32 %a, %b + %and = and i32 %a, %rhs + %res = icmp eq i32 %and, 1 + ret i1 %res +} + +; Negative test - even number +define i1 @test5(i32 %a) { +; CHECK-LABEL: @test5( +; CHECK: [[RHS:%.*]] = add i32 %a, 2 +; CHECK-NEXT: [[AND:%.*]] = and i32 %a, [[RHS]] +; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[AND]], 1 +; CHECK-NEXT: ret i1 [[RES]] +; + %rhs = add i32 %a, 2 + %and = and i32 %a, %rhs + %res = icmp eq i32 %and, 1 + ret i1 %res +} + +define i1 @test6(i32 %a) { +; CHECK-LABEL: @test6( +; CHECK: ret i1 false +; + %lhs = add i32 %a, -1 + %and = and i32 %lhs, %a + %res = icmp eq i32 %and, 1 + ret i1 %res +} diff --git a/llvm/test/Transforms/InstSimplify/add.ll b/llvm/test/Transforms/InstSimplify/add.ll new file mode 100644 index 00000000000..21cc905688b --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/add.ll @@ -0,0 +1,51 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @common_sub_operand(i32 %X, i32 %Y) { +; CHECK-LABEL: @common_sub_operand( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %Z = sub i32 %X, %Y + %Q = add i32 %Z, %Y + ret i32 %Q +} + +define i32 @negated_operand(i32 %x) { +; CHECK-LABEL: @negated_operand( +; CHECK-NEXT: ret i32 0 +; + %negx = sub i32 0, %x + %r = add i32 %negx, %x + ret i32 %r +} + +define <2 x i32> @negated_operand_commute_vec(<2 x i32> %x) { +; CHECK-LABEL: @negated_operand_commute_vec( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %negx = sub <2 x i32> zeroinitializer, %x + %r = add <2 x i32> %x, %negx + ret <2 x i32> %r +} + +define i8 @knownnegation(i8 %x, i8 %y) { +; CHECK-LABEL: @knownnegation( +; CHECK-NEXT: ret i8 0 +; + %xy = sub i8 %x, %y + %yx = sub i8 %y, %x + %r = add i8 %xy, %yx + ret i8 %r +} + +define <2 x i8> @knownnegation_commute_vec(<2 x i8> %x, <2 x i8> %y) { +; CHECK-LABEL: @knownnegation_commute_vec( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %xy = sub <2 x i8> %x, %y + %yx = sub <2 x i8> %y, %x + %r = add <2 x i8> %yx, %xy + ret <2 x i8> %r +} + + diff --git a/llvm/test/Transforms/InstSimplify/addsub.ll b/llvm/test/Transforms/InstSimplify/addsub.ll new file mode 100644 index 00000000000..2f19a4d205e --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/addsub.ll @@ -0,0 +1,78 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i1 @test1(i1 %a) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: ret i1 true +; + %b = xor i1 %a, true + %res = sub i1 %a, %b + ret i1 %res +} + +define <2 x i1> @test2(<2 x i1> %a) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %b = xor <2 x i1> %a, <i1 true, i1 true> + %res = sub <2 x i1> %a, %b + ret <2 x i1> %res +} + +define i1 @test5(i1 %a) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: ret i1 false +; + %res = add i1 %a, %a + ret i1 %res +} + +define <2 x i1> @test6(<2 x i1> %a) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %res = add <2 x i1> %a, %a + ret <2 x i1> %res +} + +define i1 @test7(i1 %a) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: ret i1 [[A:%.*]] +; + %c = xor i1 %a, true + %res = add i1 %c, true + ret i1 %res +} + +; TODO: simplify this to %a +define i1 @test8(i1 %a) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: [[C:%.*]] = add i1 [[A:%.*]], true +; CHECK-NEXT: [[RES:%.*]] = xor i1 [[C]], true +; CHECK-NEXT: ret i1 [[RES]] +; + %c = add i1 %a, true + %res = xor i1 %c, true + ret i1 %res +} + +define i1 @test9(i1 %a) { +; CHECK-LABEL: @test9( +; CHECK-NEXT: ret i1 [[A:%.*]] +; + %c = xor i1 %a, true + %res = sub i1 %c, true + ret i1 %res +} + +; TODO: simplify this to %a +define i1 @test10(i1 %a) { +; CHECK-LABEL: @test10( +; CHECK-NEXT: [[C:%.*]] = sub i1 [[A:%.*]], true +; CHECK-NEXT: [[RES:%.*]] = xor i1 [[C]], true +; CHECK-NEXT: ret i1 [[RES]] +; + %c = sub i1 %a, true + %res = xor i1 %c, true + ret i1 %res +} diff --git a/llvm/test/Transforms/InstSimplify/and-icmps-same-ops.ll b/llvm/test/Transforms/InstSimplify/and-icmps-same-ops.ll new file mode 100644 index 00000000000..4da79388f72 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/and-icmps-same-ops.ll @@ -0,0 +1,1239 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; There are 10 * 10 combinations of icmp predicates that can be AND'd together. +; The majority of these can be simplified to always false or just one of the icmps. + +define i1 @eq_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ne( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_sgt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_slt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ugt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @eq_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ult( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @ne_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_eq( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_sgt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_slt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ugt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ne_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ult( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @sge_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_eq( +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_sgt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_slt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sge_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @sgt_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_eq( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_sle( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_slt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sgt_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @sle_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_eq( +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_sgt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_slt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @sle_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @slt_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_eq( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_sge( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_sgt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @slt_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @uge_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_eq( +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ugt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @uge_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ult( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @ugt_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_eq( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ule( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ugt_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ult( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @ule_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_eq( +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ugt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ule_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ult( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; + +define i1 @ult_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_eq( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ne( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_uge( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ugt( +; CHECK-NEXT: ret i1 false +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +; Check a couple of vector variants to make sure those work too. + +define <2 x i1> @ult_uge_vec(<2 x i8> %a, <2 x i8> %b) { +; CHECK-LABEL: @ult_uge_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %cmp1 = icmp ult <2 x i8> %a, %b + %cmp2 = icmp uge <2 x i8> %a, %b + %and = and <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %and +} + +define <2 x i1> @ult_ule_vec(<2 x i8> %a, <2 x i8> %b) { +; CHECK-LABEL: @ult_ule_vec( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i8> %a, %b +; CHECK-NEXT: ret <2 x i1> [[CMP1]] +; + %cmp1 = icmp ult <2 x i8> %a, %b + %cmp2 = icmp ule <2 x i8> %a, %b + %and = and <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %and +} + +define i1 @ult_uge_swap(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_uge_swap( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %b, %a +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp uge i8 %b, %a + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @ult_ult_swap(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ult_swap( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %b, %a +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ult i8 %b, %a + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + diff --git a/llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll b/llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll new file mode 100644 index 00000000000..04bf5ace36a --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll @@ -0,0 +1,263 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; In the next 16 tests (4 commutes * 2 (and/or) * 2 optional ptrtoint casts), +; eliminate the simple (not) null check because that compare is implied by the +; masked compare of the same operand. +; Vary types between scalar and vector and weird for extra coverage. + +; or (icmp eq (and X, ?), 0), (icmp eq X, 0) --> icmp eq (and X, ?), 0 + +define i1 @or_cmps_eq_zero_with_mask_commute1(i64 %x, i64 %y) { +; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute1( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i64 %x, %y +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i64 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq i64 %x, 0 + %somebits = and i64 %x, %y + %somebits_are_zero = icmp eq i64 %somebits, 0 + %r = or i1 %somebits_are_zero, %isnull + ret i1 %r +} + +; or (icmp eq X, 0), (icmp eq (and X, ?), 0) --> icmp eq (and X, ?), 0 + +define <2 x i1> @or_cmps_eq_zero_with_mask_commute2(<2 x i64> %x, <2 x i64> %y) { +; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute2( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <2 x i64> %x, %y +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i64> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq <2 x i64> %x, zeroinitializer + %somebits = and <2 x i64> %x, %y + %somebits_are_zero = icmp eq <2 x i64> %somebits, zeroinitializer + %r = or <2 x i1> %isnull, %somebits_are_zero + ret <2 x i1> %r +} + +; or (icmp eq (and ?, X), 0), (icmp eq X, 0) --> icmp eq (and ?, X), 0 + +define i1 @or_cmps_eq_zero_with_mask_commute3(i4 %x, i4 %y) { +; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute3( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i4 %y, %x +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i4 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq i4 %x, 0 + %somebits = and i4 %y, %x + %somebits_are_zero = icmp eq i4 %somebits, 0 + %r = or i1 %somebits_are_zero, %isnull + ret i1 %r +} + +; or (icmp eq X, 0), (icmp eq (and ?, X), 0) --> icmp eq (and ?, X), 0 + +define <2 x i1> @or_cmps_eq_zero_with_mask_commute4(<2 x i4> %x, <2 x i4> %y) { +; CHECK-LABEL: @or_cmps_eq_zero_with_mask_commute4( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <2 x i4> %y, %x +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i4> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq <2 x i4> %x, zeroinitializer + %somebits = and <2 x i4> %y, %x + %somebits_are_zero = icmp eq <2 x i4> %somebits, zeroinitializer + %r = or <2 x i1> %isnull, %somebits_are_zero + ret <2 x i1> %r +} + +; and (icmp ne (and X, ?), 0), (icmp ne X, 0) --> icmp ne (and X, ?), 0 + +define <3 x i1> @and_cmps_eq_zero_with_mask_commute1(<3 x i4> %x, <3 x i4> %y) { +; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute1( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <3 x i4> %x, %y +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i4> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne <3 x i4> %x, zeroinitializer + %somebits = and <3 x i4> %x, %y + %somebits_are_not_zero = icmp ne <3 x i4> %somebits, zeroinitializer + %r = and <3 x i1> %somebits_are_not_zero, %isnotnull + ret <3 x i1> %r +} + +; and (icmp ne X, 0), (icmp ne (and X, ?), 0) --> icmp ne (and X, ?), 0 + +define i1 @and_cmps_eq_zero_with_mask_commute2(i4 %x, i4 %y) { +; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute2( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i4 %x, %y +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i4 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne i4 %x, 0 + %somebits = and i4 %x, %y + %somebits_are_not_zero = icmp ne i4 %somebits, 0 + %r = and i1 %isnotnull, %somebits_are_not_zero + ret i1 %r +} + +; and (icmp ne (and ?, X), 0), (icmp ne X, 0) --> icmp ne (and ?, X), 0 + +define <3 x i1> @and_cmps_eq_zero_with_mask_commute3(<3 x i64> %x, <3 x i64> %y) { +; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute3( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <3 x i64> %y, %x +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i64> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne <3 x i64> %x, zeroinitializer + %somebits = and <3 x i64> %y, %x + %somebits_are_not_zero = icmp ne <3 x i64> %somebits, zeroinitializer + %r = and <3 x i1> %somebits_are_not_zero, %isnotnull + ret <3 x i1> %r +} + +; and (icmp ne X, 0), (icmp ne (and ?, X), 0) --> icmp ne (and ?, X), 0 + +define i1 @and_cmps_eq_zero_with_mask_commute4(i64 %x, i64 %y) { +; CHECK-LABEL: @and_cmps_eq_zero_with_mask_commute4( +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i64 %y, %x +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i64 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne i64 %x, 0 + %somebits = and i64 %y, %x + %somebits_are_not_zero = icmp ne i64 %somebits, 0 + %r = and i1 %isnotnull, %somebits_are_not_zero + ret i1 %r +} + +; or (icmp eq (and (ptrtoint P), ?), 0), (icmp eq P, 0) --> icmp eq (and (ptrtoint P), ?), 0 + +define i1 @or_cmps_ptr_eq_zero_with_mask_commute1(i64* %p, i64 %y) { +; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute1( +; CHECK-NEXT: [[X:%.*]] = ptrtoint i64* %p to i64 +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i64 [[X]], %y +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i64 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq i64* %p, null + %x = ptrtoint i64* %p to i64 + %somebits = and i64 %x, %y + %somebits_are_zero = icmp eq i64 %somebits, 0 + %r = or i1 %somebits_are_zero, %isnull + ret i1 %r +} + +; or (icmp eq P, 0), (icmp eq (and (ptrtoint P), ?), 0) --> icmp eq (and (ptrtoint P), ?), 0 + +define <2 x i1> @or_cmps_ptr_eq_zero_with_mask_commute2(<2 x i64*> %p, <2 x i64> %y) { +; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute2( +; CHECK-NEXT: [[X:%.*]] = ptrtoint <2 x i64*> %p to <2 x i64> +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <2 x i64> [[X]], %y +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i64> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq <2 x i64*> %p, zeroinitializer + %x = ptrtoint <2 x i64*> %p to <2 x i64> + %somebits = and <2 x i64> %x, %y + %somebits_are_zero = icmp eq <2 x i64> %somebits, zeroinitializer + %r = or <2 x i1> %isnull, %somebits_are_zero + ret <2 x i1> %r +} + +; or (icmp eq (and ?, (ptrtoint P)), 0), (icmp eq P, 0) --> icmp eq (and ?, (ptrtoint P)), 0 + +define i1 @or_cmps_ptr_eq_zero_with_mask_commute3(i4* %p, i4 %y) { +; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute3( +; CHECK-NEXT: [[X:%.*]] = ptrtoint i4* %p to i4 +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i4 %y, [[X]] +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq i4 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq i4* %p, null + %x = ptrtoint i4* %p to i4 + %somebits = and i4 %y, %x + %somebits_are_zero = icmp eq i4 %somebits, 0 + %r = or i1 %somebits_are_zero, %isnull + ret i1 %r +} + +; or (icmp eq P, 0), (icmp eq (and ?, (ptrtoint P)), 0) --> icmp eq (and ?, (ptrtoint P)), 0 + +define <2 x i1> @or_cmps_ptr_eq_zero_with_mask_commute4(<2 x i4*> %p, <2 x i4> %y) { +; CHECK-LABEL: @or_cmps_ptr_eq_zero_with_mask_commute4( +; CHECK-NEXT: [[X:%.*]] = ptrtoint <2 x i4*> %p to <2 x i4> +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <2 x i4> %y, [[X]] +; CHECK-NEXT: [[SOMEBITS_ARE_ZERO:%.*]] = icmp eq <2 x i4> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[SOMEBITS_ARE_ZERO]] +; + %isnull = icmp eq <2 x i4*> %p, zeroinitializer + %x = ptrtoint <2 x i4*> %p to <2 x i4> + %somebits = and <2 x i4> %y, %x + %somebits_are_zero = icmp eq <2 x i4> %somebits, zeroinitializer + %r = or <2 x i1> %isnull, %somebits_are_zero + ret <2 x i1> %r +} + +; and (icmp ne (and (ptrtoint P), ?), 0), (icmp ne P, 0) --> icmp ne (and (ptrtoint P), ?), 0 + +define <3 x i1> @and_cmps_ptr_eq_zero_with_mask_commute1(<3 x i4*> %p, <3 x i4> %y) { +; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute1( +; CHECK-NEXT: [[X:%.*]] = ptrtoint <3 x i4*> %p to <3 x i4> +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <3 x i4> [[X]], %y +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i4> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne <3 x i4*> %p, zeroinitializer + %x = ptrtoint <3 x i4*> %p to <3 x i4> + %somebits = and <3 x i4> %x, %y + %somebits_are_not_zero = icmp ne <3 x i4> %somebits, zeroinitializer + %r = and <3 x i1> %somebits_are_not_zero, %isnotnull + ret <3 x i1> %r +} + +; and (icmp ne P, 0), (icmp ne (and (ptrtoint P), ?), 0) --> icmp ne (and (ptrtoint P), ?), 0 + +define i1 @and_cmps_ptr_eq_zero_with_mask_commute2(i4* %p, i4 %y) { +; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute2( +; CHECK-NEXT: [[X:%.*]] = ptrtoint i4* %p to i4 +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i4 [[X]], %y +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i4 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne i4* %p, null + %x = ptrtoint i4* %p to i4 + %somebits = and i4 %x, %y + %somebits_are_not_zero = icmp ne i4 %somebits, 0 + %r = and i1 %isnotnull, %somebits_are_not_zero + ret i1 %r +} + +; and (icmp ne (and ?, (ptrtoint P)), 0), (icmp ne P, 0) --> icmp ne (and ?, (ptrtoint P)), 0 + +define <3 x i1> @and_cmps_ptr_eq_zero_with_mask_commute3(<3 x i64*> %p, <3 x i64> %y) { +; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute3( +; CHECK-NEXT: [[X:%.*]] = ptrtoint <3 x i64*> %p to <3 x i64> +; CHECK-NEXT: [[SOMEBITS:%.*]] = and <3 x i64> %y, [[X]] +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne <3 x i64> [[SOMEBITS]], zeroinitializer +; CHECK-NEXT: ret <3 x i1> [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne <3 x i64*> %p, zeroinitializer + %x = ptrtoint <3 x i64*> %p to <3 x i64> + %somebits = and <3 x i64> %y, %x + %somebits_are_not_zero = icmp ne <3 x i64> %somebits, zeroinitializer + %r = and <3 x i1> %somebits_are_not_zero, %isnotnull + ret <3 x i1> %r +} + +; and (icmp ne P, 0), (icmp ne (and ?, (ptrtoint P)), 0) --> icmp ne (and ?, (ptrtoint P)), 0 + +define i1 @and_cmps_ptr_eq_zero_with_mask_commute4(i64* %p, i64 %y) { +; CHECK-LABEL: @and_cmps_ptr_eq_zero_with_mask_commute4( +; CHECK-NEXT: [[X:%.*]] = ptrtoint i64* %p to i64 +; CHECK-NEXT: [[SOMEBITS:%.*]] = and i64 %y, [[X]] +; CHECK-NEXT: [[SOMEBITS_ARE_NOT_ZERO:%.*]] = icmp ne i64 [[SOMEBITS]], 0 +; CHECK-NEXT: ret i1 [[SOMEBITS_ARE_NOT_ZERO]] +; + %isnotnull = icmp ne i64* %p, null + %x = ptrtoint i64* %p to i64 + %somebits = and i64 %y, %x + %somebits_are_not_zero = icmp ne i64 %somebits, 0 + %r = and i1 %isnotnull, %somebits_are_not_zero + ret i1 %r +} + diff --git a/llvm/test/Transforms/InstSimplify/assume.ll b/llvm/test/Transforms/InstSimplify/assume.ll new file mode 100644 index 00000000000..99b5759e958 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/assume.ll @@ -0,0 +1,93 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt -instsimplify -S < %s 2>&1 -pass-remarks-analysis=.* | FileCheck %s + +; Verify that warnings are emitted for the 2nd and 3rd tests. + +; CHECK: remark: /tmp/s.c:1:13: Detected conflicting code assumptions. +; CHECK: remark: /tmp/s.c:4:10: Detected conflicting code assumptions. +; CHECK: remark: /tmp/s.c:5:50: Detected conflicting code assumptions. + +define void @test1() { +; CHECK-LABEL: @test1( +; CHECK: ret void +; + call void @llvm.assume(i1 1) + ret void + +} + +; The alloca guarantees that the low bits of %a are zero because of alignment. +; The assume says the opposite. The assume is processed last, so that's the +; return value. There's no way to win (we can't undo transforms that happened +; based on half-truths), so just don't crash. + +define i64 @PR31809() !dbg !7 { +; CHECK-LABEL: @PR31809( +; CHECK-NEXT: ret i64 3 +; + %a = alloca i32 + %t1 = ptrtoint i32* %a to i64, !dbg !9 + %cond = icmp eq i64 %t1, 3 + call void @llvm.assume(i1 %cond) + ret i64 %t1 +} + +; Similar to above: there's no way to know which assumption is truthful, +; so just don't crash. The second icmp+assume gets processed later, so that +; determines the return value. + +define i8 @conflicting_assumptions(i8 %x) !dbg !10 { +; CHECK-LABEL: @conflicting_assumptions( +; CHECK-NEXT: call void @llvm.assume(i1 false) +; CHECK-NEXT: [[COND2:%.*]] = icmp eq i8 %x, 4 +; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]]) +; CHECK-NEXT: ret i8 5 +; + %add = add i8 %x, 1, !dbg !11 + %cond1 = icmp eq i8 %x, 3 + call void @llvm.assume(i1 %cond1) + %cond2 = icmp eq i8 %x, 4 + call void @llvm.assume(i1 %cond2) + ret i8 %add +} + +; Another case of conflicting assumptions. This would crash because we'd +; try to set more known bits than existed in the known bits struct. + +define void @PR36270(i32 %b) !dbg !13 { +; CHECK-LABEL: @PR36270( +; CHECK-NEXT: tail call void @llvm.assume(i1 false) +; CHECK-NEXT: unreachable +; + %B7 = xor i32 -1, 2147483647 + %and1 = and i32 %b, 3 + %B12 = lshr i32 %B7, %and1, !dbg !14 + %C1 = icmp ult i32 %and1, %B12 + tail call void @llvm.assume(i1 %C1) + %cmp2 = icmp eq i32 0, %B12 + tail call void @llvm.assume(i1 %cmp2) + unreachable +} + +declare void @llvm.assume(i1) nounwind + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 282540) (llvm/trunk 282542)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2) +!1 = !DIFile(filename: "/tmp/s.c", directory: "/tmp") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"PIC Level", i32 2} +!6 = !{!"clang version 4.0.0 (trunk 282540) (llvm/trunk 282542)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !2) +!9 = !DILocation(line: 1, column: 13, scope: !7) +!10 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, retainedNodes: !2) +!11 = !DILocation(line: 4, column: 10, scope: !10) +!12 = !DILocation(line: 4, column: 3, scope: !10) +!13 = distinct !DISubprogram(name: "PR36270", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, retainedNodes: !2) +!14 = !DILocation(line: 5, column: 50, scope: !13) + diff --git a/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll b/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll new file mode 100644 index 00000000000..608c95688f3 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll @@ -0,0 +1,277 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-f64:32:64-v64:64:64-v128:128:128" + +define <2 x i64> @test1() { +; CHECK-LABEL: @test1( +; CHECK-NEXT: ret <2 x i64> <i64 4294967296, i64 12884901890> +; + %tmp3 = bitcast <4 x i32> < i32 0, i32 1, i32 2, i32 3 > to <2 x i64> + ret <2 x i64> %tmp3 +} + +define <4 x i32> @test2() { +; CHECK-LABEL: @test2( +; CHECK-NEXT: ret <4 x i32> <i32 0, i32 0, i32 1, i32 0> +; + %tmp3 = bitcast <2 x i64> < i64 0, i64 1 > to <4 x i32> + ret <4 x i32> %tmp3 +} + +define <2 x double> @test3() { +; CHECK-LABEL: @test3( +; CHECK-NEXT: ret <2 x double> <double 0x100000000, double 0x300000002> +; + %tmp3 = bitcast <4 x i32> < i32 0, i32 1, i32 2, i32 3 > to <2 x double> + ret <2 x double> %tmp3 +} + +define <4 x float> @test4() { +; CHECK-LABEL: @test4( +; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0x36A0000000000000, float 0.000000e+00> +; + %tmp3 = bitcast <2 x i64> < i64 0, i64 1 > to <4 x float> + ret <4 x float> %tmp3 +} + +define <2 x i64> @test5() { +; CHECK-LABEL: @test5( +; CHECK-NEXT: ret <2 x i64> <i64 4575657221408423936, i64 4629700418010611712> +; + %tmp3 = bitcast <4 x float> <float 0.0, float 1.0, float 2.0, float 3.0> to <2 x i64> + ret <2 x i64> %tmp3 +} + +define <4 x i32> @test6() { +; CHECK-LABEL: @test6( +; CHECK-NEXT: ret <4 x i32> <i32 0, i32 1071644672, i32 0, i32 1072693248> +; + %tmp3 = bitcast <2 x double> <double 0.5, double 1.0> to <4 x i32> + ret <4 x i32> %tmp3 +} + +define i32 @test7() { +; CHECK-LABEL: @test7( +; CHECK-NEXT: ret i32 1118464 +; + %tmp3 = bitcast <2 x half> <half 0xH1100, half 0xH0011> to i32 + ret i32 %tmp3 +} + +define <4 x i32> @test8(<1 x i64> %y) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: ret <4 x i32> zeroinitializer +; + %c = bitcast <2 x i64> <i64 0, i64 0> to <4 x i32> + ret <4 x i32> %c +} + +define <4 x i32> @test9(<1 x i64> %y) { +; CHECK-LABEL: @test9( +; CHECK-NEXT: ret <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1> +; + %c = bitcast <2 x i64> <i64 -1, i64 -1> to <4 x i32> + ret <4 x i32> %c +} + +define <1 x i1> @test10() { +; CHECK-LABEL: @test10( +; CHECK-NEXT: ret <1 x i1> <i1 icmp eq (i64 bitcast (<1 x double> <double 0xFFFFFFFFFFFFFFFF> to i64), i64 0)> +; + %ret = icmp eq <1 x i64> <i64 bitcast (<1 x double> <double 0xFFFFFFFFFFFFFFFF> to i64)>, zeroinitializer + ret <1 x i1> %ret +} + +; from MultiSource/Benchmarks/Bullet +define <2 x float> @foo() { +; CHECK-LABEL: @foo( +; CHECK-NEXT: ret <2 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000> +; + %cast = bitcast i64 -1 to <2 x float> + ret <2 x float> %cast +} + + +define <2 x double> @foo2() { +; CHECK-LABEL: @foo2( +; CHECK-NEXT: ret <2 x double> <double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF> +; + %cast = bitcast i128 -1 to <2 x double> + ret <2 x double> %cast +} + +define <1 x float> @foo3() { +; CHECK-LABEL: @foo3( +; CHECK-NEXT: ret <1 x float> <float 0xFFFFFFFFE0000000> +; + %cast = bitcast i32 -1 to <1 x float> + ret <1 x float> %cast +} + +define float @foo4() { +; CHECK-LABEL: @foo4( +; CHECK-NEXT: ret float 0xFFFFFFFFE0000000 +; + %cast = bitcast <1 x i32 ><i32 -1> to float + ret float %cast +} + +define double @foo5() { +; CHECK-LABEL: @foo5( +; CHECK-NEXT: ret double 0xFFFFFFFFFFFFFFFF +; + %cast = bitcast <2 x i32 ><i32 -1, i32 -1> to double + ret double %cast +} + +define <2 x double> @foo6() { +; CHECK-LABEL: @foo6( +; CHECK-NEXT: ret <2 x double> <double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF> +; + %cast = bitcast <4 x i32><i32 -1, i32 -1, i32 -1, i32 -1> to <2 x double> + ret <2 x double> %cast +} + +define <4 x i32> @bitcast_constexpr_4i32_2i64_u2() { +; CHECK-LABEL: @bitcast_constexpr_4i32_2i64_u2( +; CHECK-NEXT: ret <4 x i32> <i32 undef, i32 undef, i32 2, i32 0> +; + %cast = bitcast <2 x i64><i64 undef, i64 2> to <4 x i32> + ret <4 x i32> %cast +} + +define <4 x i32> @bitcast_constexpr_4i32_2i64_1u() { +; CHECK-LABEL: @bitcast_constexpr_4i32_2i64_1u( +; CHECK-NEXT: ret <4 x i32> <i32 1, i32 0, i32 undef, i32 undef> +; + %cast = bitcast <2 x i64><i64 1, i64 undef> to <4 x i32> + ret <4 x i32> %cast +} + +define <4 x i32> @bitcast_constexpr_4i32_2i64() { +; CHECK-LABEL: @bitcast_constexpr_4i32_2i64( +; CHECK-NEXT: ret <4 x i32> <i32 undef, i32 undef, i32 2, i32 0> +; + %cast = bitcast <2 x i64><i64 undef, i64 2> to <4 x i32> + ret <4 x i32> %cast +} + +define <8 x i16> @bitcast_constexpr_8i16_2i64_u2() { +; CHECK-LABEL: @bitcast_constexpr_8i16_2i64_u2( +; CHECK-NEXT: ret <8 x i16> <i16 undef, i16 undef, i16 undef, i16 undef, i16 2, i16 0, i16 0, i16 0> +; + %cast = bitcast <2 x i64><i64 undef, i64 2> to <8 x i16> + ret <8 x i16> %cast +} + +define <8 x i16> @bitcast_constexpr_8i16_2i64_1u() { +; CHECK-LABEL: @bitcast_constexpr_8i16_2i64_1u( +; CHECK-NEXT: ret <8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 undef, i16 undef, i16 undef, i16 undef> +; + %cast = bitcast <2 x i64><i64 1, i64 undef> to <8 x i16> + ret <8 x i16> %cast +} + +define <8 x i16> @bitcast_constexpr_8i16_2i64_u65536() { +; CHECK-LABEL: @bitcast_constexpr_8i16_2i64_u65536( +; CHECK-NEXT: ret <8 x i16> <i16 undef, i16 undef, i16 undef, i16 undef, i16 0, i16 1, i16 0, i16 0> +; + %cast = bitcast <2 x i64><i64 undef, i64 65536> to <8 x i16> + ret <8 x i16> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_2i64_u2() { +; CHECK-LABEL: @bitcast_constexpr_16i8_2i64_u2( +; CHECK-NEXT: ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 2, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0> +; + %cast = bitcast <2 x i64><i64 undef, i64 2> to <16 x i8> + ret <16 x i8> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_2i64_256u() { +; CHECK-LABEL: @bitcast_constexpr_16i8_2i64_256u( +; CHECK-NEXT: ret <16 x i8> <i8 0, i8 1, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef> +; + %cast = bitcast <2 x i64><i64 256, i64 undef> to <16 x i8> + ret <16 x i8> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_2i64_u256() { +; CHECK-LABEL: @bitcast_constexpr_16i8_2i64_u256( +; CHECK-NEXT: ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 0, i8 1, i8 0, i8 0, i8 0, i8 0, i8 0, i8 0> +; + %cast = bitcast <2 x i64><i64 undef, i64 256> to <16 x i8> + ret <16 x i8> %cast +} + +define <8 x i16> @bitcast_constexpr_8i16_4i32_uu22() { +; CHECK-LABEL: @bitcast_constexpr_8i16_4i32_uu22( +; CHECK-NEXT: ret <8 x i16> <i16 undef, i16 undef, i16 undef, i16 undef, i16 2, i16 0, i16 2, i16 0> +; + %cast = bitcast <4 x i32><i32 undef, i32 undef, i32 2, i32 2> to <8 x i16> + ret <8 x i16> %cast +} + +define <8 x i16> @bitcast_constexpr_8i16_4i32_10uu() { +; CHECK-LABEL: @bitcast_constexpr_8i16_4i32_10uu( +; CHECK-NEXT: ret <8 x i16> <i16 1, i16 0, i16 0, i16 0, i16 undef, i16 undef, i16 undef, i16 undef> +; + %cast = bitcast <4 x i32><i32 1, i32 0, i32 undef, i32 undef> to <8 x i16> + ret <8 x i16> %cast +} + +define <8 x i16> @bitcast_constexpr_8i16_4i32_u257u256() { +; CHECK-LABEL: @bitcast_constexpr_8i16_4i32_u257u256( +; CHECK-NEXT: ret <8 x i16> <i16 undef, i16 undef, i16 0, i16 1, i16 undef, i16 undef, i16 0, i16 1> +; + %cast = bitcast <4 x i32><i32 undef, i32 65536, i32 undef, i32 65536> to <8 x i16> + ret <8 x i16> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_4i32_u2u2() { +; CHECK-LABEL: @bitcast_constexpr_16i8_4i32_u2u2( +; CHECK-NEXT: ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 2, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 2, i8 0, i8 0, i8 0> +; + %cast = bitcast <4 x i32><i32 undef, i32 2, i32 undef, i32 2> to <16 x i8> + ret <16 x i8> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_4i32_1u1u() { +; CHECK-LABEL: @bitcast_constexpr_16i8_4i32_1u1u( +; CHECK-NEXT: ret <16 x i8> <i8 1, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 1, i8 0, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef> +; + %cast = bitcast <4 x i32><i32 1, i32 undef, i32 1, i32 undef> to <16 x i8> + ret <16 x i8> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_4i32_u256uu() { +; CHECK-LABEL: @bitcast_constexpr_16i8_4i32_u256uu( +; CHECK-NEXT: ret <16 x i8> <i8 undef, i8 undef, i8 undef, i8 undef, i8 0, i8 1, i8 0, i8 0, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef> +; + %cast = bitcast <4 x i32><i32 undef, i32 256, i32 undef, i32 undef> to <16 x i8> + ret <16 x i8> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_8i16_u2u2u2u2() { +; CHECK-LABEL: @bitcast_constexpr_16i8_8i16_u2u2u2u2( +; CHECK-NEXT: ret <16 x i8> <i8 undef, i8 undef, i8 2, i8 0, i8 undef, i8 undef, i8 2, i8 0, i8 undef, i8 undef, i8 2, i8 0, i8 undef, i8 undef, i8 2, i8 0> +; + %cast = bitcast <8 x i16><i16 undef, i16 2, i16 undef, i16 2, i16 undef, i16 2, i16 undef, i16 2> to <16 x i8> + ret <16 x i8> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_8i16_1u1u1u1u() { +; CHECK-LABEL: @bitcast_constexpr_16i8_8i16_1u1u1u1u( +; CHECK-NEXT: ret <16 x i8> <i8 1, i8 0, i8 undef, i8 undef, i8 1, i8 0, i8 undef, i8 undef, i8 1, i8 0, i8 undef, i8 undef, i8 1, i8 0, i8 undef, i8 undef> +; + %cast = bitcast <8 x i16><i16 1, i16 undef, i16 1, i16 undef, i16 1, i16 undef, i16 1, i16 undef> to <16 x i8> + ret <16 x i8> %cast +} + +define <16 x i8> @bitcast_constexpr_16i8_8i16_u256uuu256uu() { +; CHECK-LABEL: @bitcast_constexpr_16i8_8i16_u256uuu256uu( +; CHECK-NEXT: ret <16 x i8> <i8 undef, i8 undef, i8 0, i8 1, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 undef, i8 0, i8 1, i8 undef, i8 undef, i8 undef, i8 undef> +; + %cast = bitcast <8 x i16><i16 undef, i16 256, i16 undef, i16 undef, i16 undef, i16 256, i16 undef, i16 undef> to <16 x i8> + ret <16 x i8> %cast +} diff --git a/llvm/test/Transforms/InstSimplify/bitreverse-fold.ll b/llvm/test/Transforms/InstSimplify/bitreverse-fold.ll new file mode 100644 index 00000000000..eab4b07a16e --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/bitreverse-fold.ll @@ -0,0 +1,110 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @identity_bitreverse_i32(i32 %p) { +; CHECK-LABEL: @identity_bitreverse_i32( +; CHECK-NEXT: ret i32 %p + %a = call i32 @llvm.bitreverse.i32(i32 %p) + %b = call i32 @llvm.bitreverse.i32(i32 %a) + ret i32 %b +} + +; CHECK-LABEL: @identity_bitreverse_v2i32( +; CHECK-NEXT: ret <2 x i32> %p +define <2 x i32> @identity_bitreverse_v2i32(<2 x i32> %p) { + %a = call <2 x i32> @llvm.bitreverse.v2i32(<2 x i32> %p) + %b = call <2 x i32> @llvm.bitreverse.v2i32(<2 x i32> %a) + ret <2 x i32> %b +} + +; CHECK-LABEL: @reverse_0_i32( +; CHECK-NEXT: ret i32 0 +define i32 @reverse_0_i32() { + %x = call i32 @llvm.bitreverse.i32(i32 0) + ret i32 %x +} + +; CHECK-LABEL: @reverse_1_i32( +; CHECK-NEXT: ret i32 -2147483648 +define i32 @reverse_1_i32() { + %x = call i32 @llvm.bitreverse.i32(i32 1) + ret i32 %x +} + +; CHECK-LABEL: @reverse_neg1_i32( +; CHECK-NEXT: ret i32 -1 +define i32 @reverse_neg1_i32() { + %x = call i32 @llvm.bitreverse.i32(i32 -1) + ret i32 %x +} + +; CHECK-LABEL: @reverse_undef_i32( +; CHECK-NEXT: ret i32 undef +define i32 @reverse_undef_i32() { + %x = call i32 @llvm.bitreverse.i32(i32 undef) + ret i32 %x +} + +; CHECK-LABEL: @reverse_false_i1( +; CHECK-NEXT: ret i1 false +define i1 @reverse_false_i1() { + %x = call i1 @llvm.bitreverse.i1(i1 false) + ret i1 %x +} + +; CHECK-LABEL: @reverse_true_i1( +; CHECK-NEXT: ret i1 true +define i1 @reverse_true_i1() { + %x = call i1 @llvm.bitreverse.i1(i1 true) + ret i1 %x +} + +; CHECK-LABEL: @reverse_undef_i1( +; CHECK-NEXT: ret i1 undef +define i1 @reverse_undef_i1() { + %x = call i1 @llvm.bitreverse.i1(i1 undef) + ret i1 %x +} + +; CHECK-LABEL: @reverse_false_v2i1( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +define <2 x i1> @reverse_false_v2i1() { + %x = call <2 x i1> @llvm.bitreverse.v2i1(<2 x i1> zeroinitializer) + ret <2 x i1> %x +} + +; CHECK-LABEL: @reverse_true_v2i1( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +define <2 x i1> @reverse_true_v2i1() { + %x = call <2 x i1> @llvm.bitreverse.v2i1(<2 x i1> <i1 true, i1 true>) + ret <2 x i1> %x +} + +; CHECK-LABEL: @bitreverse_920_1234_v2i32( +; CHECK-NEXT: ret <2 x i32> <i32 432013312, i32 1260388352> +define <2 x i32> @bitreverse_920_1234_v2i32() { + %x = call <2 x i32> @llvm.bitreverse.v2i32(<2 x i32> <i32 920, i32 1234>) + ret <2 x i32> %x +} + +; CHECK-LABEL: @reverse_100_i3( +; CHECK-NEXT: ret i3 1 +define i3 @reverse_100_i3() { + %x = call i3 @llvm.bitreverse.i3(i3 100) + ret i3 %x +} + +; CHECK-LABEL: @reverse_6_3_v2i3( +; CHECK-NEXT: ret <2 x i3> <i3 3, i3 -2> +define <2 x i3> @reverse_6_3_v2i3() { + %x = call <2 x i3> @llvm.bitreverse.v2i3(<2 x i3> <i3 6, i3 3>) + ret <2 x i3> %x +} + +declare i1 @llvm.bitreverse.i1(i1) readnone +declare <2 x i1> @llvm.bitreverse.v2i1(<2 x i1>) readnone + +declare i3 @llvm.bitreverse.i3(i3) readnone +declare <2 x i3> @llvm.bitreverse.v2i3(<2 x i3>) readnone + +declare i32 @llvm.bitreverse.i32(i32) readnone +declare <2 x i32> @llvm.bitreverse.v2i32(<2 x i32>) readnone diff --git a/llvm/test/Transforms/InstSimplify/bitreverse.ll b/llvm/test/Transforms/InstSimplify/bitreverse.ll new file mode 100644 index 00000000000..d87b68831fe --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/bitreverse.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -S -instsimplify | FileCheck %s + +declare i32 @llvm.bitreverse.i32(i32) + +; CHECK-LABEL: @test1( +; CHECK: ret i1 false +define i1 @test1(i32 %arg) { + %a = or i32 %arg, 1 + %b = call i32 @llvm.bitreverse.i32(i32 %a) + %res = icmp eq i32 %b, 0 + ret i1 %res +} + +; CHECK-LABEL: @test2( +; CHECK: ret i1 false +define i1 @test2(i32 %arg) { + %a = or i32 %arg, 1024 + %b = call i32 @llvm.bitreverse.i32(i32 %a) + %res = icmp eq i32 %b, 0 + ret i1 %res +} + +; CHECK-LABEL: @test3( +; CHECK: ret i1 false +define i1 @test3(i32 %arg) { + %a = and i32 %arg, 1 + %b = call i32 @llvm.bitreverse.i32(i32 %a) + %and = and i32 %b, 1 + %res = icmp eq i32 %and, 1 + ret i1 %res +} diff --git a/llvm/test/Transforms/InstSimplify/bswap.ll b/llvm/test/Transforms/InstSimplify/bswap.ll new file mode 100644 index 00000000000..5c67aa0a764 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/bswap.ll @@ -0,0 +1,46 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt < %s -S -instsimplify | FileCheck %s + +declare i16 @llvm.bswap.i16(i16) + +define i1 @test1(i16 %arg) { +; CHECK-LABEL: @test1( +; CHECK: ret i1 false +; + %a = or i16 %arg, 1 + %b = call i16 @llvm.bswap.i16(i16 %a) + %res = icmp eq i16 %b, 0 + ret i1 %res +} + +define i1 @test2(i16 %arg) { +; CHECK-LABEL: @test2( +; CHECK: ret i1 false +; + %a = or i16 %arg, 1024 + %b = call i16 @llvm.bswap.i16(i16 %a) + %res = icmp eq i16 %b, 0 + ret i1 %res +} + +define i1 @test3(i16 %arg) { +; CHECK-LABEL: @test3( +; CHECK: ret i1 false +; + %a = and i16 %arg, 1 + %b = call i16 @llvm.bswap.i16(i16 %a) + %and = and i16 %b, 1 + %res = icmp eq i16 %and, 1 + ret i1 %res +} + +define i1 @test4(i16 %arg) { +; CHECK-LABEL: @test4( +; CHECK: ret i1 false +; + %a = and i16 %arg, 511 + %b = call i16 @llvm.bswap.i16(i16 %a) + %and = and i16 %b, 256 + %res = icmp eq i16 %and, 1 + ret i1 %res +} diff --git a/llvm/test/Transforms/InstSimplify/call.ll b/llvm/test/Transforms/InstSimplify/call.ll new file mode 100644 index 00000000000..0771e4453e3 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/call.ll @@ -0,0 +1,744 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s +; RUN: opt < %s -passes=instsimplify -S | FileCheck %s + +declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b) +declare {i8, i1} @llvm.sadd.with.overflow.i8(i8 %a, i8 %b) +declare {i8, i1} @llvm.usub.with.overflow.i8(i8 %a, i8 %b) +declare {i8, i1} @llvm.ssub.with.overflow.i8(i8 %a, i8 %b) +declare {i8, i1} @llvm.umul.with.overflow.i8(i8 %a, i8 %b) +declare {i8, i1} @llvm.smul.with.overflow.i8(i8 %a, i8 %b) + +define i1 @test_uadd1() { +; CHECK-LABEL: @test_uadd1( +; CHECK-NEXT: ret i1 true +; + %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 3) + %overflow = extractvalue {i8, i1} %x, 1 + ret i1 %overflow +} + +define i8 @test_uadd2() { +; CHECK-LABEL: @test_uadd2( +; CHECK-NEXT: ret i8 42 +; + %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 44) + %result = extractvalue {i8, i1} %x, 0 + ret i8 %result +} + +define {i8, i1} @test_uadd3(i8 %v) { +; CHECK-LABEL: @test_uadd3( +; CHECK-NEXT: ret { i8, i1 } undef +; + %result = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 %v, i8 undef) + ret {i8, i1} %result +} + +define {i8, i1} @test_uadd4(i8 %v) { +; CHECK-LABEL: @test_uadd4( +; CHECK-NEXT: ret { i8, i1 } undef +; + %result = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 undef, i8 %v) + ret {i8, i1} %result +} + +define i1 @test_sadd1() { +; CHECK-LABEL: @test_sadd1( +; CHECK-NEXT: ret i1 true +; + %x = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 126, i8 3) + %overflow = extractvalue {i8, i1} %x, 1 + ret i1 %overflow +} + +define i8 @test_sadd2() { +; CHECK-LABEL: @test_sadd2( +; CHECK-NEXT: ret i8 -86 +; + %x = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 126, i8 44) + %result = extractvalue {i8, i1} %x, 0 + ret i8 %result +} + +define {i8, i1} @test_sadd3(i8 %v) { +; CHECK-LABEL: @test_sadd3( +; CHECK-NEXT: ret { i8, i1 } undef +; + %result = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 %v, i8 undef) + ret {i8, i1} %result +} + +define {i8, i1} @test_sadd4(i8 %v) { +; CHECK-LABEL: @test_sadd4( +; CHECK-NEXT: ret { i8, i1 } undef +; + %result = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 undef, i8 %v) + ret {i8, i1} %result +} + +define {i8, i1} @test_usub1(i8 %V) { +; CHECK-LABEL: @test_usub1( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.usub.with.overflow.i8(i8 %V, i8 %V) + ret {i8, i1} %x +} + +define {i8, i1} @test_usub2(i8 %V) { +; CHECK-LABEL: @test_usub2( +; CHECK-NEXT: ret { i8, i1 } undef +; + %x = call {i8, i1} @llvm.usub.with.overflow.i8(i8 %V, i8 undef) + ret {i8, i1} %x +} + +define {i8, i1} @test_usub3(i8 %V) { +; CHECK-LABEL: @test_usub3( +; CHECK-NEXT: ret { i8, i1 } undef +; + %x = call {i8, i1} @llvm.usub.with.overflow.i8(i8 undef, i8 %V) + ret {i8, i1} %x +} + +define {i8, i1} @test_ssub1(i8 %V) { +; CHECK-LABEL: @test_ssub1( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 %V, i8 %V) + ret {i8, i1} %x +} + +define {i8, i1} @test_ssub2(i8 %V) { +; CHECK-LABEL: @test_ssub2( +; CHECK-NEXT: ret { i8, i1 } undef +; + %x = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 %V, i8 undef) + ret {i8, i1} %x +} + +define {i8, i1} @test_ssub3(i8 %V) { +; CHECK-LABEL: @test_ssub3( +; CHECK-NEXT: ret { i8, i1 } undef +; + %x = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 undef, i8 %V) + ret {i8, i1} %x +} + +define {i8, i1} @test_umul1(i8 %V) { +; CHECK-LABEL: @test_umul1( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 %V, i8 0) + ret {i8, i1} %x +} + +define {i8, i1} @test_umul2(i8 %V) { +; CHECK-LABEL: @test_umul2( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 %V, i8 undef) + ret {i8, i1} %x +} + +define {i8, i1} @test_umul3(i8 %V) { +; CHECK-LABEL: @test_umul3( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 0, i8 %V) + ret {i8, i1} %x +} + +define {i8, i1} @test_umul4(i8 %V) { +; CHECK-LABEL: @test_umul4( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 undef, i8 %V) + ret {i8, i1} %x +} + +define {i8, i1} @test_smul1(i8 %V) { +; CHECK-LABEL: @test_smul1( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 %V, i8 0) + ret {i8, i1} %x +} + +define {i8, i1} @test_smul2(i8 %V) { +; CHECK-LABEL: @test_smul2( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 %V, i8 undef) + ret {i8, i1} %x +} + +define {i8, i1} @test_smul3(i8 %V) { +; CHECK-LABEL: @test_smul3( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 0, i8 %V) + ret {i8, i1} %x +} + +define {i8, i1} @test_smul4(i8 %V) { +; CHECK-LABEL: @test_smul4( +; CHECK-NEXT: ret { i8, i1 } zeroinitializer +; + %x = call {i8, i1} @llvm.smul.with.overflow.i8(i8 undef, i8 %V) + ret {i8, i1} %x +} + +; Test a non-intrinsic that we know about as a library call. +declare float @fabs(float %x) + +define float @test_fabs_libcall() { +; CHECK-LABEL: @test_fabs_libcall( +; CHECK-NEXT: [[X:%.*]] = call float @fabs(float -4.200000e+01) +; CHECK-NEXT: ret float 4.200000e+01 +; + + %x = call float @fabs(float -42.0) +; This is still a real function call, so instsimplify won't nuke it -- other +; passes have to do that. + + ret float %x +} + + +declare float @llvm.fabs.f32(float) nounwind readnone +declare float @llvm.floor.f32(float) nounwind readnone +declare float @llvm.ceil.f32(float) nounwind readnone +declare float @llvm.trunc.f32(float) nounwind readnone +declare float @llvm.rint.f32(float) nounwind readnone +declare float @llvm.nearbyint.f32(float) nounwind readnone +declare float @llvm.canonicalize.f32(float) nounwind readnone + +; Test idempotent intrinsics +define float @test_idempotence(float %a) { +; CHECK-LABEL: @test_idempotence( +; CHECK-NEXT: [[A0:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) +; CHECK-NEXT: [[B0:%.*]] = call float @llvm.floor.f32(float [[A]]) +; CHECK-NEXT: [[C0:%.*]] = call float @llvm.ceil.f32(float [[A]]) +; CHECK-NEXT: [[D0:%.*]] = call float @llvm.trunc.f32(float [[A]]) +; CHECK-NEXT: [[E0:%.*]] = call float @llvm.rint.f32(float [[A]]) +; CHECK-NEXT: [[F0:%.*]] = call float @llvm.nearbyint.f32(float [[A]]) +; CHECK-NEXT: [[G0:%.*]] = call float @llvm.canonicalize.f32(float [[A]]) +; CHECK-NEXT: [[R0:%.*]] = fadd float [[A0]], [[B0]] +; CHECK-NEXT: [[R1:%.*]] = fadd float [[R0]], [[C0]] +; CHECK-NEXT: [[R2:%.*]] = fadd float [[R1]], [[D0]] +; CHECK-NEXT: [[R3:%.*]] = fadd float [[R2]], [[E0]] +; CHECK-NEXT: [[R4:%.*]] = fadd float [[R3]], [[F0]] +; CHECK-NEXT: [[R5:%.*]] = fadd float [[R4]], [[G0]] +; CHECK-NEXT: ret float [[R5]] +; + + %a0 = call float @llvm.fabs.f32(float %a) + %a1 = call float @llvm.fabs.f32(float %a0) + + %b0 = call float @llvm.floor.f32(float %a) + %b1 = call float @llvm.floor.f32(float %b0) + + %c0 = call float @llvm.ceil.f32(float %a) + %c1 = call float @llvm.ceil.f32(float %c0) + + %d0 = call float @llvm.trunc.f32(float %a) + %d1 = call float @llvm.trunc.f32(float %d0) + + %e0 = call float @llvm.rint.f32(float %a) + %e1 = call float @llvm.rint.f32(float %e0) + + %f0 = call float @llvm.nearbyint.f32(float %a) + %f1 = call float @llvm.nearbyint.f32(float %f0) + + %g0 = call float @llvm.canonicalize.f32(float %a) + %g1 = call float @llvm.canonicalize.f32(float %g0) + + %r0 = fadd float %a1, %b1 + %r1 = fadd float %r0, %c1 + %r2 = fadd float %r1, %d1 + %r3 = fadd float %r2, %e1 + %r4 = fadd float %r3, %f1 + %r5 = fadd float %r4, %g1 + + ret float %r5 +} + +define i8* @operator_new() { +; CHECK-LABEL: @operator_new( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @_Znwm(i64 8) +; CHECK-NEXT: br i1 false, label [[CAST_END:%.*]], label [[CAST_NOTNULL:%.*]] +; CHECK: cast.notnull: +; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 4 +; CHECK-NEXT: br label [[CAST_END]] +; CHECK: cast.end: +; CHECK-NEXT: [[CAST_RESULT:%.*]] = phi i8* [ [[ADD_PTR]], [[CAST_NOTNULL]] ], [ null, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i8* [[CAST_RESULT]] +; +entry: + %call = tail call noalias i8* @_Znwm(i64 8) + %cmp = icmp eq i8* %call, null + br i1 %cmp, label %cast.end, label %cast.notnull + +cast.notnull: ; preds = %entry + %add.ptr = getelementptr inbounds i8, i8* %call, i64 4 + br label %cast.end + +cast.end: ; preds = %cast.notnull, %entry + %cast.result = phi i8* [ %add.ptr, %cast.notnull ], [ null, %entry ] + ret i8* %cast.result + +} + +declare nonnull noalias i8* @_Znwm(i64) + +%"struct.std::nothrow_t" = type { i8 } +@_ZSt7nothrow = external global %"struct.std::nothrow_t" + +define i8* @operator_new_nothrow_t() { +; CHECK-LABEL: @operator_new_nothrow_t( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @_ZnamRKSt9nothrow_t(i64 8, %"struct.std::nothrow_t"* @_ZSt7nothrow) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[CALL]], null +; CHECK-NEXT: br i1 [[CMP]], label [[CAST_END:%.*]], label [[CAST_NOTNULL:%.*]] +; CHECK: cast.notnull: +; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 4 +; CHECK-NEXT: br label [[CAST_END]] +; CHECK: cast.end: +; CHECK-NEXT: [[CAST_RESULT:%.*]] = phi i8* [ [[ADD_PTR]], [[CAST_NOTNULL]] ], [ null, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i8* [[CAST_RESULT]] +; +entry: + %call = tail call noalias i8* @_ZnamRKSt9nothrow_t(i64 8, %"struct.std::nothrow_t"* @_ZSt7nothrow) + %cmp = icmp eq i8* %call, null + br i1 %cmp, label %cast.end, label %cast.notnull + +cast.notnull: ; preds = %entry + %add.ptr = getelementptr inbounds i8, i8* %call, i64 4 + br label %cast.end + +cast.end: ; preds = %cast.notnull, %entry + %cast.result = phi i8* [ %add.ptr, %cast.notnull ], [ null, %entry ] + ret i8* %cast.result + +} + +declare i8* @_ZnamRKSt9nothrow_t(i64, %"struct.std::nothrow_t"*) nounwind + +define i8* @malloc_can_return_null() { +; CHECK-LABEL: @malloc_can_return_null( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @malloc(i64 8) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[CALL]], null +; CHECK-NEXT: br i1 [[CMP]], label [[CAST_END:%.*]], label [[CAST_NOTNULL:%.*]] +; CHECK: cast.notnull: +; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 4 +; CHECK-NEXT: br label [[CAST_END]] +; CHECK: cast.end: +; CHECK-NEXT: [[CAST_RESULT:%.*]] = phi i8* [ [[ADD_PTR]], [[CAST_NOTNULL]] ], [ null, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i8* [[CAST_RESULT]] +; +entry: + %call = tail call noalias i8* @malloc(i64 8) + %cmp = icmp eq i8* %call, null + br i1 %cmp, label %cast.end, label %cast.notnull + +cast.notnull: ; preds = %entry + %add.ptr = getelementptr inbounds i8, i8* %call, i64 4 + br label %cast.end + +cast.end: ; preds = %cast.notnull, %entry + %cast.result = phi i8* [ %add.ptr, %cast.notnull ], [ null, %entry ] + ret i8* %cast.result + +} + +define i32 @call_null() { +; CHECK-LABEL: @call_null( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = call i32 null() +; CHECK-NEXT: ret i32 undef +; +entry: + %call = call i32 null() + ret i32 %call +} + +define i32 @call_undef() { +; CHECK-LABEL: @call_undef( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = call i32 undef() +; CHECK-NEXT: ret i32 undef +; +entry: + %call = call i32 undef() + ret i32 %call +} + +@GV = private constant [8 x i32] [i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48, i32 49] + +define <8 x i32> @partial_masked_load() { +; CHECK-LABEL: @partial_masked_load( +; CHECK-NEXT: ret <8 x i32> <i32 undef, i32 undef, i32 42, i32 43, i32 44, i32 45, i32 46, i32 47> +; + %masked.load = call <8 x i32> @llvm.masked.load.v8i32.p0v8i32(<8 x i32>* bitcast (i32* getelementptr ([8 x i32], [8 x i32]* @GV, i64 0, i64 -2) to <8 x i32>*), i32 4, <8 x i1> <i1 false, i1 false, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>, <8 x i32> undef) + ret <8 x i32> %masked.load +} + +define <8 x i32> @masked_load_undef_mask(<8 x i32>* %V) { +; CHECK-LABEL: @masked_load_undef_mask( +; CHECK-NEXT: ret <8 x i32> <i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0> +; + %masked.load = call <8 x i32> @llvm.masked.load.v8i32.p0v8i32(<8 x i32>* %V, i32 4, <8 x i1> undef, <8 x i32> <i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0>) + ret <8 x i32> %masked.load +} + +declare noalias i8* @malloc(i64) + +declare <8 x i32> @llvm.masked.load.v8i32.p0v8i32(<8 x i32>*, i32, <8 x i1>, <8 x i32>) + +declare double @llvm.powi.f64(double, i32) +declare <2 x double> @llvm.powi.v2f64(<2 x double>, i32) + +define double @constant_fold_powi() { +; CHECK-LABEL: @constant_fold_powi( +; CHECK-NEXT: ret double 9.000000e+00 +; + %t0 = call double @llvm.powi.f64(double 3.00000e+00, i32 2) + ret double %t0 +} + +define <2 x double> @constant_fold_powi_vec() { +; CHECK-LABEL: @constant_fold_powi_vec( +; CHECK-NEXT: ret <2 x double> <double 9.000000e+00, double 2.500000e+01> +; + %t0 = call <2 x double> @llvm.powi.v2f64(<2 x double> <double 3.00000e+00, double 5.00000e+00>, i32 2) + ret <2 x double> %t0 +} + +declare i8 @llvm.fshl.i8(i8, i8, i8) +declare i9 @llvm.fshr.i9(i9, i9, i9) +declare <2 x i7> @llvm.fshl.v2i7(<2 x i7>, <2 x i7>, <2 x i7>) +declare <2 x i8> @llvm.fshr.v2i8(<2 x i8>, <2 x i8>, <2 x i8>) + +define i8 @fshl_no_shift(i8 %x, i8 %y) { +; CHECK-LABEL: @fshl_no_shift( +; CHECK-NEXT: ret i8 [[X:%.*]] +; + %z = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 0) + ret i8 %z +} + +define i9 @fshr_no_shift(i9 %x, i9 %y) { +; CHECK-LABEL: @fshr_no_shift( +; CHECK-NEXT: ret i9 [[Y:%.*]] +; + %z = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 0) + ret i9 %z +} + +define i8 @fshl_no_shift_modulo_bitwidth(i8 %x, i8 %y) { +; CHECK-LABEL: @fshl_no_shift_modulo_bitwidth( +; CHECK-NEXT: ret i8 [[X:%.*]] +; + %z = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 40) + ret i8 %z +} + +define i9 @fshr_no_shift_modulo_bitwidth(i9 %x, i9 %y) { +; CHECK-LABEL: @fshr_no_shift_modulo_bitwidth( +; CHECK-NEXT: ret i9 [[Y:%.*]] +; + %z = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 189) + ret i9 %z +} + +define <2 x i7> @fshl_no_shift_modulo_bitwidth_splat(<2 x i7> %x, <2 x i7> %y) { +; CHECK-LABEL: @fshl_no_shift_modulo_bitwidth_splat( +; CHECK-NEXT: ret <2 x i7> [[X:%.*]] +; + %z = call <2 x i7> @llvm.fshl.v2i7(<2 x i7> %x, <2 x i7> %y, <2 x i7> <i7 21, i7 21>) + ret <2 x i7> %z +} + +define <2 x i8> @fshr_no_shift_modulo_bitwidth_splat(<2 x i8> %x, <2 x i8> %y) { +; CHECK-LABEL: @fshr_no_shift_modulo_bitwidth_splat( +; CHECK-NEXT: ret <2 x i8> [[Y:%.*]] +; + %z = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> %x, <2 x i8> %y, <2 x i8> <i8 72, i8 72>) + ret <2 x i8> %z +} + +; If y is poison, eliminating the guard is not safe. + +define i8 @fshl_zero_shift_guard(i8 %x, i8 %y, i8 %sh) { +; CHECK-LABEL: @fshl_zero_shift_guard( +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[SH:%.*]], 0 +; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]]) +; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[X]], i8 [[F]] +; CHECK-NEXT: ret i8 [[S]] +; + %c = icmp eq i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh) + %s = select i1 %c, i8 %x, i8 %f + ret i8 %s +} + +; If y is poison, eliminating the guard is not safe. + +define i8 @fshl_zero_shift_guard_swapped(i8 %x, i8 %y, i8 %sh) { +; CHECK-LABEL: @fshl_zero_shift_guard_swapped( +; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[SH:%.*]], 0 +; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]]) +; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[F]], i8 [[X]] +; CHECK-NEXT: ret i8 [[S]] +; + %c = icmp ne i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh) + %s = select i1 %c, i8 %f, i8 %x + ret i8 %s +} + +; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted. + +define i8 @fshl_zero_shift_guard_inverted(i8 %x, i8 %y, i8 %sh) { +; CHECK-LABEL: @fshl_zero_shift_guard_inverted( +; CHECK-NEXT: ret i8 [[X:%.*]] +; + %c = icmp eq i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh) + %s = select i1 %c, i8 %f, i8 %x + ret i8 %s +} + +; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted. + +define i8 @fshl_zero_shift_guard_inverted_swapped(i8 %x, i8 %y, i8 %sh) { +; CHECK-LABEL: @fshl_zero_shift_guard_inverted_swapped( +; CHECK-NEXT: ret i8 [[X:%.*]] +; + %c = icmp ne i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh) + %s = select i1 %c, i8 %x, i8 %f + ret i8 %s +} + +; If x is poison, eliminating the guard is not safe. + +define i9 @fshr_zero_shift_guard(i9 %x, i9 %y, i9 %sh) { +; CHECK-LABEL: @fshr_zero_shift_guard( +; CHECK-NEXT: [[C:%.*]] = icmp eq i9 [[SH:%.*]], 0 +; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]]) +; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i9 [[Y]], i9 [[F]] +; CHECK-NEXT: ret i9 [[S]] +; + %c = icmp eq i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh) + %s = select i1 %c, i9 %y, i9 %f + ret i9 %s +} + +; If x is poison, eliminating the guard is not safe. + +define i9 @fshr_zero_shift_guard_swapped(i9 %x, i9 %y, i9 %sh) { +; CHECK-LABEL: @fshr_zero_shift_guard_swapped( +; CHECK-NEXT: [[C:%.*]] = icmp ne i9 [[SH:%.*]], 0 +; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]]) +; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i9 [[F]], i9 [[Y]] +; CHECK-NEXT: ret i9 [[S]] +; + %c = icmp ne i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh) + %s = select i1 %c, i9 %f, i9 %y + ret i9 %s +} + +; When the shift amount is 0, fshr returns its 2nd parameter (y), so everything is deleted. + +define i9 @fshr_zero_shift_guard_inverted(i9 %x, i9 %y, i9 %sh) { +; CHECK-LABEL: @fshr_zero_shift_guard_inverted( +; CHECK-NEXT: ret i9 [[Y:%.*]] +; + %c = icmp eq i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh) + %s = select i1 %c, i9 %f, i9 %y + ret i9 %s +} + +; When the shift amount is 0, fshr returns its 2nd parameter (y), so everything is deleted. + +define i9 @fshr_zero_shift_guard_inverted_swapped(i9 %x, i9 %y, i9 %sh) { +; CHECK-LABEL: @fshr_zero_shift_guard_inverted_swapped( +; CHECK-NEXT: ret i9 [[Y:%.*]] +; + %c = icmp ne i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh) + %s = select i1 %c, i9 %y, i9 %f + ret i9 %s +} + +; When the shift amount is 0, fshl returns its 1st parameter (x), so the guard is not needed. + +define i8 @rotl_zero_shift_guard(i8 %x, i8 %sh) { +; CHECK-LABEL: @rotl_zero_shift_guard( +; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[SH:%.*]]) +; CHECK-NEXT: ret i8 [[F]] +; + %c = icmp eq i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh) + %s = select i1 %c, i8 %x, i8 %f + ret i8 %s +} + +; When the shift amount is 0, fshl returns its 1st parameter (x), so the guard is not needed. + +define i8 @rotl_zero_shift_guard_swapped(i8 %x, i8 %sh) { +; CHECK-LABEL: @rotl_zero_shift_guard_swapped( +; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[SH:%.*]]) +; CHECK-NEXT: ret i8 [[F]] +; + %c = icmp ne i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh) + %s = select i1 %c, i8 %f, i8 %x + ret i8 %s +} + +; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted. + +define i8 @rotl_zero_shift_guard_inverted(i8 %x, i8 %sh) { +; CHECK-LABEL: @rotl_zero_shift_guard_inverted( +; CHECK-NEXT: ret i8 [[X:%.*]] +; + %c = icmp eq i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh) + %s = select i1 %c, i8 %f, i8 %x + ret i8 %s +} + +; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted. + +define i8 @rotl_zero_shift_guard_inverted_swapped(i8 %x, i8 %sh) { +; CHECK-LABEL: @rotl_zero_shift_guard_inverted_swapped( +; CHECK-NEXT: ret i8 [[X:%.*]] +; + %c = icmp ne i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %sh) + %s = select i1 %c, i8 %x, i8 %f + ret i8 %s +} + +; When the shift amount is 0, fshr returns its 2nd parameter (x), so the guard is not needed. + +define i9 @rotr_zero_shift_guard(i9 %x, i9 %sh) { +; CHECK-LABEL: @rotr_zero_shift_guard( +; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[X]], i9 [[SH:%.*]]) +; CHECK-NEXT: ret i9 [[F]] +; + %c = icmp eq i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh) + %s = select i1 %c, i9 %x, i9 %f + ret i9 %s +} + +; When the shift amount is 0, fshr returns its 2nd parameter (x), so the guard is not needed. + +define i9 @rotr_zero_shift_guard_swapped(i9 %x, i9 %sh) { +; CHECK-LABEL: @rotr_zero_shift_guard_swapped( +; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[X]], i9 [[SH:%.*]]) +; CHECK-NEXT: ret i9 [[F]] +; + %c = icmp ne i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh) + %s = select i1 %c, i9 %f, i9 %x + ret i9 %s +} + +; When the shift amount is 0, fshr returns its 2nd parameter (x), so everything is deleted. + +define i9 @rotr_zero_shift_guard_inverted(i9 %x, i9 %sh) { +; CHECK-LABEL: @rotr_zero_shift_guard_inverted( +; CHECK-NEXT: ret i9 [[X:%.*]] +; + %c = icmp eq i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh) + %s = select i1 %c, i9 %f, i9 %x + ret i9 %s +} + +; When the shift amount is 0, fshr returns its 2nd parameter (x), so everything is deleted. + +define i9 @rotr_zero_shift_guard_inverted_swapped(i9 %x, i9 %sh) { +; CHECK-LABEL: @rotr_zero_shift_guard_inverted_swapped( +; CHECK-NEXT: ret i9 [[X:%.*]] +; + %c = icmp ne i9 %sh, 0 + %f = call i9 @llvm.fshr.i9(i9 %x, i9 %x, i9 %sh) + %s = select i1 %c, i9 %x, i9 %f + ret i9 %s +} + +; Negative test - make sure we're matching the correct parameter of fshl. + +define i8 @fshl_zero_shift_guard_wrong_select_op(i8 %x, i8 %y, i8 %sh) { +; CHECK-LABEL: @fshl_zero_shift_guard_wrong_select_op( +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[SH:%.*]], 0 +; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]]) +; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[Y]], i8 [[F]] +; CHECK-NEXT: ret i8 [[S]] +; + %c = icmp eq i8 %sh, 0 + %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh) + %s = select i1 %c, i8 %y, i8 %f + ret i8 %s +} + +; Vector types work too. + +define <2 x i8> @rotr_zero_shift_guard_splat(<2 x i8> %x, <2 x i8> %sh) { +; CHECK-LABEL: @rotr_zero_shift_guard_splat( +; CHECK-NEXT: [[F:%.*]] = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[X]], <2 x i8> [[SH:%.*]]) +; CHECK-NEXT: ret <2 x i8> [[F]] +; + %c = icmp eq <2 x i8> %sh, zeroinitializer + %f = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> %x, <2 x i8> %x, <2 x i8> %sh) + %s = select <2 x i1> %c, <2 x i8> %x, <2 x i8> %f + ret <2 x i8> %s +} + +; If first two operands of funnel shift are undef, the result is undef + +define i8 @fshl_ops_undef(i8 %shamt) { +; CHECK-LABEL: @fshl_ops_undef( +; CHECK-NEXT: ret i8 undef +; + %r = call i8 @llvm.fshl.i8(i8 undef, i8 undef, i8 %shamt) + ret i8 %r +} + +define i9 @fshr_ops_undef(i9 %shamt) { +; CHECK-LABEL: @fshr_ops_undef( +; CHECK-NEXT: ret i9 undef +; + %r = call i9 @llvm.fshr.i9(i9 undef, i9 undef, i9 %shamt) + ret i9 %r +} + +; If shift amount is undef, treat it as zero, returning operand 0 or 1 + +define i8 @fshl_shift_undef(i8 %x, i8 %y) { +; CHECK-LABEL: @fshl_shift_undef( +; CHECK-NEXT: ret i8 [[X:%.*]] +; + %r = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 undef) + ret i8 %r +} + +define i9 @fshr_shift_undef(i9 %x, i9 %y) { +; CHECK-LABEL: @fshr_shift_undef( +; CHECK-NEXT: ret i9 [[Y:%.*]] +; + %r = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 undef) + ret i9 %r +} + diff --git a/llvm/test/Transforms/InstSimplify/cast-unsigned-icmp-cmp-0.ll b/llvm/test/Transforms/InstSimplify/cast-unsigned-icmp-cmp-0.ll new file mode 100644 index 00000000000..3c068c8deb0 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/cast-unsigned-icmp-cmp-0.ll @@ -0,0 +1,188 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; This is related to https://bugs.llvm.org/show_bug.cgi?id=36682 + +; All of these can be simplified to a constant true or false value. +; * slt i32 %b, 0 -> false +; * sgt i32 %b, -1 -> true + +define i1 @i32_cast_cmp_slt_int_0_uitofp_float(i32 %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_float( +; CHECK-NEXT: ret i1 false +; + %f = uitofp i32 %i to float + %b = bitcast float %f to i32 + %cmp = icmp slt i32 %b, 0 + ret i1 %cmp +} + +define <2 x i1> @i32_cast_cmp_slt_int_0_uitofp_float_vec(<2 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_float_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %f = uitofp <2 x i32> %i to <2 x float> + %b = bitcast <2 x float> %f to <2 x i32> + %cmp = icmp slt <2 x i32> %b, <i32 0, i32 0> + ret <2 x i1> %cmp +} + +define <3 x i1> @i32_cast_cmp_slt_int_0_uitofp_float_vec_undef(<3 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_float_vec_undef( +; CHECK-NEXT: ret <3 x i1> zeroinitializer +; + %f = uitofp <3 x i32> %i to <3 x float> + %b = bitcast <3 x float> %f to <3 x i32> + %cmp = icmp slt <3 x i32> %b, <i32 0, i32 undef, i32 0> + ret <3 x i1> %cmp +} + +define i1 @i32_cast_cmp_sgt_int_m1_uitofp_float(i32 %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_float( +; CHECK-NEXT: ret i1 true +; + %f = uitofp i32 %i to float + %b = bitcast float %f to i32 + %cmp = icmp sgt i32 %b, -1 + ret i1 %cmp +} + +define <2 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_float_vec(<2 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_float_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %f = uitofp <2 x i32> %i to <2 x float> + %b = bitcast <2 x float> %f to <2 x i32> + %cmp = icmp sgt <2 x i32> %b, <i32 -1, i32 -1> + ret <2 x i1> %cmp +} + +define <3 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_float_vec_undef(<3 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_float_vec_undef( +; CHECK-NEXT: ret <3 x i1> <i1 true, i1 true, i1 true> +; + %f = uitofp <3 x i32> %i to <3 x float> + %b = bitcast <3 x float> %f to <3 x i32> + %cmp = icmp sgt <3 x i32> %b, <i32 -1, i32 undef, i32 -1> + ret <3 x i1> %cmp +} + +define i1 @i32_cast_cmp_slt_int_0_uitofp_double(i32 %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_double( +; CHECK-NEXT: ret i1 false +; + %f = uitofp i32 %i to double + %b = bitcast double %f to i64 + %cmp = icmp slt i64 %b, 0 + ret i1 %cmp +} + +define <2 x i1> @i32_cast_cmp_slt_int_0_uitofp_double_vec(<2 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_double_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %f = uitofp <2 x i32> %i to <2 x double> + %b = bitcast <2 x double> %f to <2 x i64> + %cmp = icmp slt <2 x i64> %b, <i64 0, i64 0> + ret <2 x i1> %cmp +} + +define <3 x i1> @i32_cast_cmp_slt_int_0_uitofp_double_vec_undef(<3 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_double_vec_undef( +; CHECK-NEXT: ret <3 x i1> zeroinitializer +; + %f = uitofp <3 x i32> %i to <3 x double> + %b = bitcast <3 x double> %f to <3 x i64> + %cmp = icmp slt <3 x i64> %b, <i64 0, i64 undef, i64 0> + ret <3 x i1> %cmp +} + +define i1 @i32_cast_cmp_sgt_int_m1_uitofp_double(i32 %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_double( +; CHECK-NEXT: ret i1 true +; + %f = uitofp i32 %i to double + %b = bitcast double %f to i64 + %cmp = icmp sgt i64 %b, -1 + ret i1 %cmp +} + +define <2 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_double_vec(<2 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_double_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %f = uitofp <2 x i32> %i to <2 x double> + %b = bitcast <2 x double> %f to <2 x i64> + %cmp = icmp sgt <2 x i64> %b, <i64 -1, i64 -1> + ret <2 x i1> %cmp +} + +define <3 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_double_vec_undef(<3 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_double_vec_undef( +; CHECK-NEXT: ret <3 x i1> <i1 true, i1 true, i1 true> +; + %f = uitofp <3 x i32> %i to <3 x double> + %b = bitcast <3 x double> %f to <3 x i64> + %cmp = icmp sgt <3 x i64> %b, <i64 -1, i64 undef, i64 -1> + ret <3 x i1> %cmp +} + +define i1 @i32_cast_cmp_slt_int_0_uitofp_half(i32 %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_half( +; CHECK-NEXT: ret i1 false +; + %f = uitofp i32 %i to half + %b = bitcast half %f to i16 + %cmp = icmp slt i16 %b, 0 + ret i1 %cmp +} + +define <2 x i1> @i32_cast_cmp_slt_int_0_uitofp_half_vec(<2 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_half_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %f = uitofp <2 x i32> %i to <2 x half> + %b = bitcast <2 x half> %f to <2 x i16> + %cmp = icmp slt <2 x i16> %b, <i16 0, i16 0> + ret <2 x i1> %cmp +} + +define <3 x i1> @i32_cast_cmp_slt_int_0_uitofp_half_vec_undef(<3 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_slt_int_0_uitofp_half_vec_undef( +; CHECK-NEXT: ret <3 x i1> zeroinitializer +; + %f = uitofp <3 x i32> %i to <3 x half> + %b = bitcast <3 x half> %f to <3 x i16> + %cmp = icmp slt <3 x i16> %b, <i16 0, i16 undef, i16 0> + ret <3 x i1> %cmp +} + +define i1 @i32_cast_cmp_sgt_int_m1_uitofp_half(i32 %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_half( +; CHECK-NEXT: ret i1 true +; + %f = uitofp i32 %i to half + %b = bitcast half %f to i16 + %cmp = icmp sgt i16 %b, -1 + ret i1 %cmp +} + +define <2 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_half_vec(<2 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_half_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %f = uitofp <2 x i32> %i to <2 x half> + %b = bitcast <2 x half> %f to <2 x i16> + %cmp = icmp sgt <2 x i16> %b, <i16 -1, i16 -1> + ret <2 x i1> %cmp +} + +define <3 x i1> @i32_cast_cmp_sgt_int_m1_uitofp_half_vec_undef(<3 x i32> %i) { +; CHECK-LABEL: @i32_cast_cmp_sgt_int_m1_uitofp_half_vec_undef( +; CHECK-NEXT: ret <3 x i1> <i1 true, i1 true, i1 true> +; + %f = uitofp <3 x i32> %i to <3 x half> + %b = bitcast <3 x half> %f to <3 x i16> + %cmp = icmp sgt <3 x i16> %b, <i16 -1, i16 undef, i16 -1> + ret <3 x i1> %cmp +} diff --git a/llvm/test/Transforms/InstSimplify/cast.ll b/llvm/test/Transforms/InstSimplify/cast.ll new file mode 100644 index 00000000000..1ba3c76d023 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/cast.ll @@ -0,0 +1,54 @@ +; RUN: opt -S -instsimplify < %s | FileCheck %s +target datalayout = "p:32:32" + +define i1 @test1(i1 %V) { +entry: + %Z = zext i1 %V to i32 + %T = trunc i32 %Z to i1 + ret i1 %T +; CHECK-LABEL: define i1 @test1( +; CHECK: ret i1 %V +} + +define i8* @test2(i8* %V) { +entry: + %BC1 = bitcast i8* %V to i32* + %BC2 = bitcast i32* %BC1 to i8* + ret i8* %BC2 +; CHECK-LABEL: define i8* @test2( +; CHECK: ret i8* %V +} + +define i8* @test3(i8* %V) { +entry: + %BC = bitcast i8* %V to i8* + ret i8* %BC +; CHECK-LABEL: define i8* @test3( +; CHECK: ret i8* %V +} + +define i32 @test4() { +; CHECK-LABEL: @test4( + %alloca = alloca i32, align 4 ; alloca + 0 + %gep = getelementptr inbounds i32, i32* %alloca, i32 1 ; alloca + 4 + %bc = bitcast i32* %gep to [4 x i8]* ; alloca + 4 + %pti = ptrtoint i32* %alloca to i32 ; alloca + %sub = sub i32 0, %pti ; -alloca + %add = getelementptr [4 x i8], [4 x i8]* %bc, i32 0, i32 %sub ; alloca + 4 - alloca == 4 + %add_to_int = ptrtoint i8* %add to i32 ; 4 + ret i32 %add_to_int ; 4 +; CHECK-NEXT: ret i32 4 +} + +define i32 @test5() { +; CHECK-LABEL: @test5( + %alloca = alloca i32, align 4 ; alloca + 0 + %gep = getelementptr inbounds i32, i32* %alloca, i32 1 ; alloca + 4 + %bc = bitcast i32* %gep to [4 x i8]* ; alloca + 4 + %pti = ptrtoint i32* %alloca to i32 ; alloca + %sub = xor i32 %pti, -1 ; ~alloca + %add = getelementptr [4 x i8], [4 x i8]* %bc, i32 0, i32 %sub ; alloca + 4 - alloca - 1 == 3 + %add_to_int = ptrtoint i8* %add to i32 ; 4 + ret i32 %add_to_int ; 4 +; CHECK-NEXT: ret i32 3 +} diff --git a/llvm/test/Transforms/InstSimplify/cmp_of_min_max.ll b/llvm/test/Transforms/InstSimplify/cmp_of_min_max.ll new file mode 100644 index 00000000000..34c4a15aed1 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/cmp_of_min_max.ll @@ -0,0 +1,138 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i1 @test_umax1(i32 %n) { +; CHECK-LABEL: @test_umax1( +; CHECK-NEXT: ret i1 true +; + %c1 = icmp ugt i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp ugt i32 %s, 9 + ret i1 %c2 +} + +define i1 @test_umax2(i32 %n) { +; CHECK-LABEL: @test_umax2( +; CHECK-NEXT: [[C1:%.*]] = icmp ugt i32 [[N:%.*]], 10 +; CHECK-NEXT: ret i1 [[C1]] +; + %c1 = icmp ugt i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp ugt i32 %s, 10 + ret i1 %c2 +} + +define i1 @test_umax3(i32 %n) { +; CHECK-LABEL: @test_umax3( +; CHECK-NEXT: [[C1:%.*]] = icmp ugt i32 [[N:%.*]], 10 +; CHECK-NEXT: [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 10 +; CHECK-NEXT: [[C2:%.*]] = icmp ugt i32 [[S]], 11 +; CHECK-NEXT: ret i1 [[C2]] +; + %c1 = icmp ugt i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp ugt i32 %s, 11 + ret i1 %c2 +} + +define i1 @test_umin1(i32 %n) { +; CHECK-LABEL: @test_umin1( +; CHECK-NEXT: ret i1 true +; + %c1 = icmp ult i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp ult i32 %s, 11 + ret i1 %c2 +} + +define i1 @test_umin2(i32 %n) { +; CHECK-LABEL: @test_umin2( +; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[N:%.*]], 10 +; CHECK-NEXT: ret i1 [[C1]] +; + %c1 = icmp ult i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp ult i32 %s, 10 + ret i1 %c2 +} + +define i1 @test_umin3(i32 %n) { +; CHECK-LABEL: @test_umin3( +; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[N:%.*]], 10 +; CHECK-NEXT: [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 10 +; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[S]], 9 +; CHECK-NEXT: ret i1 [[C2]] +; + %c1 = icmp ult i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp ult i32 %s, 9 + ret i1 %c2 +} + +define i1 @test_smax1(i32 %n) { +; CHECK-LABEL: @test_smax1( +; CHECK-NEXT: ret i1 true +; + %c1 = icmp sgt i32 %n, -10 + %s = select i1 %c1, i32 %n, i32 -10 + %c2 = icmp sgt i32 %s, -11 + ret i1 %c2 +} + +define i1 @test_smax2(i32 %n) { +; CHECK-LABEL: @test_smax2( +; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[N:%.*]], -10 +; CHECK-NEXT: ret i1 [[C1]] +; + %c1 = icmp sgt i32 %n, -10 + %s = select i1 %c1, i32 %n, i32 -10 + %c2 = icmp sgt i32 %s, -10 + ret i1 %c2 +} + +define i1 @test_smax3(i32 %n) { +; CHECK-LABEL: @test_smax3( +; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[N:%.*]], -10 +; CHECK-NEXT: [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 -10 +; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[S]], -9 +; CHECK-NEXT: ret i1 [[C2]] +; + %c1 = icmp sgt i32 %n, -10 + %s = select i1 %c1, i32 %n, i32 -10 + %c2 = icmp sgt i32 %s, -9 + ret i1 %c2 +} + +define i1 @test_smin1(i32 %n) { +; CHECK-LABEL: @test_smin1( +; CHECK-NEXT: ret i1 true +; + %c1 = icmp slt i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp slt i32 %s, 11 + ret i1 %c2 +} + +define i1 @test_smin2(i32 %n) { +; CHECK-LABEL: @test_smin2( +; CHECK-NEXT: [[C1:%.*]] = icmp slt i32 [[N:%.*]], 10 +; CHECK-NEXT: ret i1 [[C1]] +; + %c1 = icmp slt i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp slt i32 %s, 10 + ret i1 %c2 +} + +define i1 @test_smin3(i32 %n) { +; CHECK-LABEL: @test_smin3( +; CHECK-NEXT: [[C1:%.*]] = icmp slt i32 [[N:%.*]], 10 +; CHECK-NEXT: [[S:%.*]] = select i1 [[C1]], i32 [[N]], i32 10 +; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[S]], 9 +; CHECK-NEXT: ret i1 [[C2]] +; + %c1 = icmp slt i32 %n, 10 + %s = select i1 %c1, i32 %n, i32 10 + %c2 = icmp slt i32 %s, 9 + ret i1 %c2 +} diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll new file mode 100644 index 00000000000..899f198d48a --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/compare.ll @@ -0,0 +1,1361 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s +target datalayout = "p:32:32" + +define i1 @ptrtoint() { +; CHECK-LABEL: @ptrtoint( + %a = alloca i8 + %tmp = ptrtoint i8* %a to i32 + %r = icmp eq i32 %tmp, 0 + ret i1 %r +; CHECK: ret i1 false +} + +define i1 @bitcast() { +; CHECK-LABEL: @bitcast( + %a = alloca i32 + %b = alloca i64 + %x = bitcast i32* %a to i8* + %y = bitcast i64* %b to i8* + %cmp = icmp eq i8* %x, %y + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +define i1 @gep() { +; CHECK-LABEL: @gep( + %a = alloca [3 x i8], align 8 + %x = getelementptr inbounds [3 x i8], [3 x i8]* %a, i32 0, i32 0 + %cmp = icmp eq i8* %x, null + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +define i1 @gep2() { +; CHECK-LABEL: @gep2( + %a = alloca [3 x i8], align 8 + %x = getelementptr inbounds [3 x i8], [3 x i8]* %a, i32 0, i32 0 + %y = getelementptr inbounds [3 x i8], [3 x i8]* %a, i32 0, i32 0 + %cmp = icmp eq i8* %x, %y + ret i1 %cmp +; CHECK-NEXT: ret i1 true +} + +; PR11238 +%gept = type { i32, i32 } +@gepy = global %gept zeroinitializer, align 8 +@gepz = extern_weak global %gept + +define i1 @gep3() { +; CHECK-LABEL: @gep3( + %x = alloca %gept, align 8 + %a = getelementptr %gept, %gept* %x, i64 0, i32 0 + %b = getelementptr %gept, %gept* %x, i64 0, i32 1 + %equal = icmp eq i32* %a, %b + ret i1 %equal +; CHECK-NEXT: ret i1 false +} + +define i1 @gep4() { +; CHECK-LABEL: @gep4( + %x = alloca %gept, align 8 + %a = getelementptr %gept, %gept* @gepy, i64 0, i32 0 + %b = getelementptr %gept, %gept* @gepy, i64 0, i32 1 + %equal = icmp eq i32* %a, %b + ret i1 %equal +; CHECK-NEXT: ret i1 false +} + +@a = common global [1 x i32] zeroinitializer, align 4 + +define i1 @PR31262() { +; CHECK-LABEL: @PR31262( +; CHECK-NEXT: ret i1 icmp uge (i32* getelementptr ([1 x i32], [1 x i32]* @a, i32 0, i32 undef), i32* getelementptr inbounds ([1 x i32], [1 x i32]* @a, i32 0, i32 0)) +; + %idx = getelementptr inbounds [1 x i32], [1 x i32]* @a, i64 0, i64 undef + %cmp = icmp uge i32* %idx, getelementptr inbounds ([1 x i32], [1 x i32]* @a, i32 0, i32 0) + ret i1 %cmp +} + +define i1 @gep5() { +; CHECK-LABEL: @gep5( + %x = alloca %gept, align 8 + %a = getelementptr inbounds %gept, %gept* %x, i64 0, i32 1 + %b = getelementptr %gept, %gept* @gepy, i64 0, i32 0 + %equal = icmp eq i32* %a, %b + ret i1 %equal +; CHECK-NEXT: ret i1 false +} + +define i1 @gep6(%gept* %x) { +; Same as @gep3 but potentially null. +; CHECK-LABEL: @gep6( + %a = getelementptr %gept, %gept* %x, i64 0, i32 0 + %b = getelementptr %gept, %gept* %x, i64 0, i32 1 + %equal = icmp eq i32* %a, %b + ret i1 %equal +; CHECK-NEXT: ret i1 false +} + +define i1 @gep7(%gept* %x) { +; CHECK-LABEL: @gep7( + %a = getelementptr %gept, %gept* %x, i64 0, i32 0 + %b = getelementptr %gept, %gept* @gepz, i64 0, i32 0 + %equal = icmp eq i32* %a, %b + ret i1 %equal +; CHECK: ret i1 %equal +} + +define i1 @gep8(%gept* %x) { +; CHECK-LABEL: @gep8( + %a = getelementptr %gept, %gept* %x, i32 1 + %b = getelementptr %gept, %gept* %x, i32 -1 + %equal = icmp ugt %gept* %a, %b + ret i1 %equal +; CHECK: ret i1 %equal +} + +define i1 @gep9(i8* %ptr) { +; CHECK-LABEL: @gep9( +; CHECK-NOT: ret +; CHECK: ret i1 true + +entry: + %first1 = getelementptr inbounds i8, i8* %ptr, i32 0 + %first2 = getelementptr inbounds i8, i8* %first1, i32 1 + %first3 = getelementptr inbounds i8, i8* %first2, i32 2 + %first4 = getelementptr inbounds i8, i8* %first3, i32 4 + %last1 = getelementptr inbounds i8, i8* %first2, i32 48 + %last2 = getelementptr inbounds i8, i8* %last1, i32 8 + %last3 = getelementptr inbounds i8, i8* %last2, i32 -4 + %last4 = getelementptr inbounds i8, i8* %last3, i32 -4 + %first.int = ptrtoint i8* %first4 to i32 + %last.int = ptrtoint i8* %last4 to i32 + %cmp = icmp ne i32 %last.int, %first.int + ret i1 %cmp +} + +define i1 @gep10(i8* %ptr) { +; CHECK-LABEL: @gep10( +; CHECK-NOT: ret +; CHECK: ret i1 true + +entry: + %first1 = getelementptr inbounds i8, i8* %ptr, i32 -2 + %first2 = getelementptr inbounds i8, i8* %first1, i32 44 + %last1 = getelementptr inbounds i8, i8* %ptr, i32 48 + %last2 = getelementptr inbounds i8, i8* %last1, i32 -6 + %first.int = ptrtoint i8* %first2 to i32 + %last.int = ptrtoint i8* %last2 to i32 + %cmp = icmp eq i32 %last.int, %first.int + ret i1 %cmp +} + +define i1 @gep11(i8* %ptr) { +; CHECK-LABEL: @gep11( +; CHECK-NOT: ret +; CHECK: ret i1 true + +entry: + %first1 = getelementptr inbounds i8, i8* %ptr, i32 -2 + %last1 = getelementptr inbounds i8, i8* %ptr, i32 48 + %last2 = getelementptr inbounds i8, i8* %last1, i32 -6 + %cmp = icmp ult i8* %first1, %last2 + ret i1 %cmp +} + +define i1 @gep12(i8* %ptr) { +; CHECK-LABEL: @gep12( +; CHECK-NOT: ret +; CHECK: ret i1 %cmp + +entry: + %first1 = getelementptr inbounds i8, i8* %ptr, i32 -2 + %last1 = getelementptr inbounds i8, i8* %ptr, i32 48 + %last2 = getelementptr inbounds i8, i8* %last1, i32 -6 + %cmp = icmp slt i8* %first1, %last2 + ret i1 %cmp +} + +define i1 @gep13(i8* %ptr) { +; CHECK-LABEL: @gep13( +; We can prove this GEP is non-null because it is inbounds. + %x = getelementptr inbounds i8, i8* %ptr, i32 1 + %cmp = icmp eq i8* %x, null + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +define i1 @gep13_no_null_opt(i8* %ptr) #0 { +; We can't prove this GEP is non-null. +; CHECK-LABEL: @gep13_no_null_opt( +; CHECK: getelementptr +; CHECK: icmp +; CHECK: ret + %x = getelementptr inbounds i8, i8* %ptr, i32 1 + %cmp = icmp eq i8* %x, null + ret i1 %cmp +} + +define i1 @gep14({ {}, i8 }* %ptr) { +; CHECK-LABEL: @gep14( +; We can't simplify this because the offset of one in the GEP actually doesn't +; move the pointer. + %x = getelementptr inbounds { {}, i8 }, { {}, i8 }* %ptr, i32 0, i32 1 + %cmp = icmp eq i8* %x, null + ret i1 %cmp +; CHECK-NOT: ret i1 false +} + +define i1 @gep15({ {}, [4 x {i8, i8}]}* %ptr, i32 %y) { +; CHECK-LABEL: @gep15( +; We can prove this GEP is non-null even though there is a user value, as we +; would necessarily violate inbounds on one side or the other. + %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, { {}, [4 x {i8, i8}]}* %ptr, i32 0, i32 1, i32 %y, i32 1 + %cmp = icmp eq i8* %x, null + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +define i1 @gep15_no_null_opt({ {}, [4 x {i8, i8}]}* %ptr, i32 %y) #0 { +; We can't prove this GEP is non-null. +; CHECK-LABEL: @gep15_no_null_opt( +; CHECK: getelementptr +; CHECK: icmp +; CHECK: ret + %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, { {}, [4 x {i8, i8}]}* %ptr, i32 0, i32 1, i32 %y, i32 1 + %cmp = icmp eq i8* %x, null + ret i1 %cmp +} + +define i1 @gep16(i8* %ptr, i32 %a) { +; CHECK-LABEL: @gep16( +; We can prove this GEP is non-null because it is inbounds and because we know +; %b is non-zero even though we don't know its value. + %b = or i32 %a, 1 + %x = getelementptr inbounds i8, i8* %ptr, i32 %b + %cmp = icmp eq i8* %x, null + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +define i1 @gep16_no_null_opt(i8* %ptr, i32 %a) #0 { +; We can't prove this GEP is non-null. +; CHECK-LABEL: @gep16_no_null_opt( +; CHECK getelementptr inbounds i8, i8* %ptr, i32 %b +; CHECK: %cmp = icmp eq i8* %x, null +; CHECK-NEXT: ret i1 %cmp + %b = or i32 %a, 1 + %x = getelementptr inbounds i8, i8* %ptr, i32 %b + %cmp = icmp eq i8* %x, null + ret i1 %cmp +} + +define i1 @gep17() { +; CHECK-LABEL: @gep17( + %alloca = alloca i32, align 4 + %bc = bitcast i32* %alloca to [4 x i8]* + %gep1 = getelementptr inbounds i32, i32* %alloca, i32 1 + %pti1 = ptrtoint i32* %gep1 to i32 + %gep2 = getelementptr inbounds [4 x i8], [4 x i8]* %bc, i32 0, i32 1 + %pti2 = ptrtoint i8* %gep2 to i32 + %cmp = icmp ugt i32 %pti1, %pti2 + ret i1 %cmp +; CHECK-NEXT: ret i1 true +} + +define i1 @zext(i32 %x) { +; CHECK-LABEL: @zext( + %e1 = zext i32 %x to i64 + %e2 = zext i32 %x to i64 + %r = icmp eq i64 %e1, %e2 + ret i1 %r +; CHECK: ret i1 true +} + +define i1 @zext2(i1 %x) { +; CHECK-LABEL: @zext2( + %e = zext i1 %x to i32 + %c = icmp ne i32 %e, 0 + ret i1 %c +; CHECK: ret i1 %x +} + +define i1 @zext3() { +; CHECK-LABEL: @zext3( + %e = zext i1 1 to i32 + %c = icmp ne i32 %e, 0 + ret i1 %c +; CHECK: ret i1 true +} + +define i1 @sext(i32 %x) { +; CHECK-LABEL: @sext( + %e1 = sext i32 %x to i64 + %e2 = sext i32 %x to i64 + %r = icmp eq i64 %e1, %e2 + ret i1 %r +; CHECK: ret i1 true +} + +define i1 @sext2(i1 %x) { +; CHECK-LABEL: @sext2( + %e = sext i1 %x to i32 + %c = icmp ne i32 %e, 0 + ret i1 %c +; CHECK: ret i1 %x +} + +define i1 @sext3() { +; CHECK-LABEL: @sext3( + %e = sext i1 1 to i32 + %c = icmp ne i32 %e, 0 + ret i1 %c +; CHECK: ret i1 true +} + +define i1 @add(i32 %x, i32 %y) { +; CHECK-LABEL: @add( + %l = lshr i32 %x, 1 + %q = lshr i32 %y, 1 + %r = or i32 %q, 1 + %s = add i32 %l, %r + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 false +} + +define i1 @add2(i8 %x, i8 %y) { +; CHECK-LABEL: @add2( + %l = or i8 %x, 128 + %r = or i8 %y, 129 + %s = add i8 %l, %r + %c = icmp eq i8 %s, 0 + ret i1 %c +; CHECK: ret i1 false +} + +define i1 @add3(i8 %x, i8 %y) { +; CHECK-LABEL: @add3( + %l = zext i8 %x to i32 + %r = zext i8 %y to i32 + %s = add i32 %l, %r + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 %c +} + +define i1 @add4(i32 %x, i32 %y) { +; CHECK-LABEL: @add4( + %z = add nsw i32 %y, 1 + %s1 = add nsw i32 %x, %y + %s2 = add nsw i32 %x, %z + %c = icmp slt i32 %s1, %s2 + ret i1 %c +; CHECK: ret i1 true +} + +define i1 @add5(i32 %x, i32 %y) { +; CHECK-LABEL: @add5( + %z = add nuw i32 %y, 1 + %s1 = add nuw i32 %x, %z + %s2 = add nuw i32 %x, %y + %c = icmp ugt i32 %s1, %s2 + ret i1 %c +; CHECK: ret i1 true +} + +define i1 @add6(i64 %A, i64 %B) { +; CHECK-LABEL: @add6( + %s1 = add i64 %A, %B + %s2 = add i64 %B, %A + %cmp = icmp eq i64 %s1, %s2 + ret i1 %cmp +; CHECK: ret i1 true +} + +define i1 @addpowtwo(i32 %x, i32 %y) { +; CHECK-LABEL: @addpowtwo( + %l = lshr i32 %x, 1 + %r = shl i32 1, %y + %s = add i32 %l, %r + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 false +} + +define i1 @or(i32 %x) { +; CHECK-LABEL: @or( + %o = or i32 %x, 1 + %c = icmp eq i32 %o, 0 + ret i1 %c +; CHECK: ret i1 false +} + +; Do not simplify if we cannot guarantee that the ConstantExpr is a non-zero +; constant. +@GV = common global i32* null +define i1 @or_constexp(i32 %x) { +; CHECK-LABEL: @or_constexp( +entry: + %0 = and i32 ptrtoint (i32** @GV to i32), 32 + %o = or i32 %x, %0 + %c = icmp eq i32 %o, 0 + ret i1 %c +; CHECK: or +; CHECK-NEXT: icmp eq +; CHECK-NOT: ret i1 false +} + +define i1 @shl1(i32 %x) { +; CHECK-LABEL: @shl1( + %s = shl i32 1, %x + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 false +} + +define i1 @shl3(i32 %X) { +; CHECK: @shl3 + %sub = shl nuw i32 4, %X + %cmp = icmp eq i32 %sub, 31 + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +define i1 @lshr1(i32 %x) { +; CHECK-LABEL: @lshr1( + %s = lshr i32 -1, %x + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 false +} + +define i1 @lshr3(i32 %x) { +; CHECK-LABEL: @lshr3( + %s = lshr i32 %x, %x + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 true +} + +define i1 @lshr4(i32 %X, i32 %Y) { +; CHECK-LABEL: @lshr4( + %A = lshr i32 %X, %Y + %C = icmp ule i32 %A, %X + ret i1 %C +; CHECK: ret i1 true +} + +define i1 @lshr5(i32 %X, i32 %Y) { +; CHECK-LABEL: @lshr5( + %A = lshr i32 %X, %Y + %C = icmp ugt i32 %A, %X + ret i1 %C +; CHECK: ret i1 false +} + +define i1 @lshr6(i32 %X, i32 %Y) { +; CHECK-LABEL: @lshr6( + %A = lshr i32 %X, %Y + %C = icmp ult i32 %X, %A + ret i1 %C +; CHECK: ret i1 false +} + +define i1 @lshr7(i32 %X, i32 %Y) { +; CHECK-LABEL: @lshr7( + %A = lshr i32 %X, %Y + %C = icmp uge i32 %X, %A + ret i1 %C +; CHECK: ret i1 true +} + +define i1 @ashr1(i32 %x) { +; CHECK-LABEL: @ashr1( + %s = ashr i32 -1, %x + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 false +} + +define i1 @ashr3(i32 %x) { +; CHECK-LABEL: @ashr3( + %s = ashr i32 %x, %x + %c = icmp eq i32 %s, 0 + ret i1 %c +; CHECK: ret i1 true +} + +define i1 @select1(i1 %cond) { +; CHECK-LABEL: @select1( + %s = select i1 %cond, i32 1, i32 0 + %c = icmp eq i32 %s, 1 + ret i1 %c +; CHECK: ret i1 %cond +} + +define i1 @select2(i1 %cond) { +; CHECK-LABEL: @select2( + %x = zext i1 %cond to i32 + %s = select i1 %cond, i32 %x, i32 0 + %c = icmp ne i32 %s, 0 + ret i1 %c +; CHECK: ret i1 %cond +} + +define i1 @select3(i1 %cond) { +; CHECK-LABEL: @select3( + %x = zext i1 %cond to i32 + %s = select i1 %cond, i32 1, i32 %x + %c = icmp ne i32 %s, 0 + ret i1 %c +; CHECK: ret i1 %cond +} + +define i1 @select4(i1 %cond) { +; CHECK-LABEL: @select4( + %invert = xor i1 %cond, 1 + %s = select i1 %invert, i32 0, i32 1 + %c = icmp ne i32 %s, 0 + ret i1 %c +; CHECK: ret i1 %cond +} + +define i1 @select5(i32 %x) { +; CHECK-LABEL: @select5( + %c = icmp eq i32 %x, 0 + %s = select i1 %c, i32 1, i32 %x + %c2 = icmp eq i32 %s, 0 + ret i1 %c2 +; CHECK: ret i1 false +} + +define i1 @select6(i32 %x) { +; CHECK-LABEL: @select6( + %c = icmp sgt i32 %x, 0 + %s = select i1 %c, i32 %x, i32 4 + %c2 = icmp eq i32 %s, 0 + ret i1 %c2 +; CHECK: ret i1 %c2 +} + +define i1 @urem1(i32 %X, i32 %Y) { +; CHECK-LABEL: @urem1( + %A = urem i32 %X, %Y + %B = icmp ult i32 %A, %Y + ret i1 %B +; CHECK: ret i1 true +} + +define i1 @urem2(i32 %X, i32 %Y) { +; CHECK-LABEL: @urem2( + %A = urem i32 %X, %Y + %B = icmp eq i32 %A, %Y + ret i1 %B +; CHECK: ret i1 false +} + +define i1 @urem4(i32 %X) { +; CHECK-LABEL: @urem4( + %A = urem i32 %X, 15 + %B = icmp ult i32 %A, 10 + ret i1 %B +; CHECK: ret i1 %B +} + +define i1 @urem5(i16 %X, i32 %Y) { +; CHECK-LABEL: @urem5( + %A = zext i16 %X to i32 + %B = urem i32 %A, %Y + %C = icmp slt i32 %B, %Y + ret i1 %C +; CHECK-NOT: ret i1 true +} + +define i1 @urem6(i32 %X, i32 %Y) { +; CHECK-LABEL: @urem6( + %A = urem i32 %X, %Y + %B = icmp ugt i32 %Y, %A + ret i1 %B +; CHECK: ret i1 true +} + +define i1 @urem7(i32 %X) { +; CHECK-LABEL: @urem7( + %A = urem i32 1, %X + %B = icmp sgt i32 %A, %X + ret i1 %B +; CHECK-NOT: ret i1 false +} + +; PR9343 #15 +; CHECK-LABEL: @srem2( +; CHECK: ret i1 false +define i1 @srem2(i16 %X, i32 %Y) { + %A = zext i16 %X to i32 + %B = add nsw i32 %A, 1 + %C = srem i32 %B, %Y + %D = icmp slt i32 %C, 0 + ret i1 %D +} + +; CHECK-LABEL: @srem3( +; CHECK-NEXT: ret i1 false +define i1 @srem3(i16 %X, i32 %Y) { + %A = zext i16 %X to i32 + %B = or i32 2147483648, %A + %C = sub nsw i32 1, %B + %D = srem i32 %C, %Y + %E = icmp slt i32 %D, 0 + ret i1 %E +} + +define i1 @udiv2(i32 %Z) { +; CHECK-LABEL: @udiv2( +; CHECK-NEXT: ret i1 true +; + %A = udiv exact i32 10, %Z + %B = udiv exact i32 20, %Z + %C = icmp ult i32 %A, %B + ret i1 %C +} + +; Exact sdiv and equality preds can simplify. + +define i1 @sdiv_exact_equality(i32 %Z) { +; CHECK-LABEL: @sdiv_exact_equality( +; CHECK-NEXT: ret i1 false +; + %A = sdiv exact i32 10, %Z + %B = sdiv exact i32 20, %Z + %C = icmp eq i32 %A, %B + ret i1 %C +} + +; But not other preds: PR32949 - https://bugs.llvm.org/show_bug.cgi?id=32949 + +define i1 @sdiv_exact_not_equality(i32 %Z) { +; CHECK-LABEL: @sdiv_exact_not_equality( +; CHECK-NEXT: [[A:%.*]] = sdiv exact i32 10, %Z +; CHECK-NEXT: [[B:%.*]] = sdiv exact i32 20, %Z +; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %A = sdiv exact i32 10, %Z + %B = sdiv exact i32 20, %Z + %C = icmp ult i32 %A, %B + ret i1 %C +} + +define i1 @udiv3(i32 %X, i32 %Y) { +; CHECK-LABEL: @udiv3( + %A = udiv i32 %X, %Y + %C = icmp ugt i32 %A, %X + ret i1 %C +; CHECK: ret i1 false +} + +define i1 @udiv4(i32 %X, i32 %Y) { +; CHECK-LABEL: @udiv4( + %A = udiv i32 %X, %Y + %C = icmp ule i32 %A, %X + ret i1 %C +; CHECK: ret i1 true +} + +; PR11340 +define i1 @udiv6(i32 %X) nounwind { +; CHECK-LABEL: @udiv6( + %A = udiv i32 1, %X + %C = icmp eq i32 %A, 0 + ret i1 %C +; CHECK: ret i1 %C +} + +define i1 @udiv7(i32 %X, i32 %Y) { +; CHECK-LABEL: @udiv7( + %A = udiv i32 %X, %Y + %C = icmp ult i32 %X, %A + ret i1 %C +; CHECK: ret i1 false +} + +define i1 @udiv8(i32 %X, i32 %Y) { +; CHECK-LABEL: @udiv8( + %A = udiv i32 %X, %Y + %C = icmp uge i32 %X, %A + ret i1 %C +; CHECK: ret i1 true +} + +define i1 @mul1(i32 %X) { +; CHECK-LABEL: @mul1( +; Square of a non-zero number is non-zero if there is no overflow. + %Y = or i32 %X, 1 + %M = mul nuw i32 %Y, %Y + %C = icmp eq i32 %M, 0 + ret i1 %C +; CHECK: ret i1 false +} + +define i1 @mul2(i32 %X) { +; CHECK-LABEL: @mul2( +; Square of a non-zero number is positive if there is no signed overflow. + %Y = or i32 %X, 1 + %M = mul nsw i32 %Y, %Y + %C = icmp sgt i32 %M, 0 + ret i1 %C +; CHECK: ret i1 true +} + +define i1 @mul3(i32 %X, i32 %Y) { +; CHECK-LABEL: @mul3( +; Product of non-negative numbers is non-negative if there is no signed overflow. + %XX = mul nsw i32 %X, %X + %YY = mul nsw i32 %Y, %Y + %M = mul nsw i32 %XX, %YY + %C = icmp sge i32 %M, 0 + ret i1 %C +; CHECK: ret i1 true +} + +define <2 x i1> @vectorselect1(<2 x i1> %cond) { +; CHECK-LABEL: @vectorselect1( + %invert = xor <2 x i1> %cond, <i1 1, i1 1> + %s = select <2 x i1> %invert, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 1, i32 1> + %c = icmp ne <2 x i32> %s, <i32 0, i32 0> + ret <2 x i1> %c +; CHECK: ret <2 x i1> %cond +} + +; PR11948 +define <2 x i1> @vectorselectcrash(i32 %arg1) { + %tobool40 = icmp ne i32 %arg1, 0 + %cond43 = select i1 %tobool40, <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1> + %cmp45 = icmp ugt <2 x i16> %cond43, <i16 73, i16 21> + ret <2 x i1> %cmp45 +} + +; PR12013 +define i1 @alloca_compare(i64 %idx) { + %sv = alloca { i32, i32, [124 x i32] } + %1 = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx + %2 = icmp eq i32* %1, null + ret i1 %2 + ; CHECK: alloca_compare + ; CHECK: ret i1 false +} + +define i1 @alloca_compare_no_null_opt(i64 %idx) #0 { +; CHECK-LABEL: alloca_compare_no_null_opt( +; CHECK: %sv = alloca { i32, i32, [124 x i32] } +; CHECK: %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx +; CHECK: %X = icmp eq i32* %cmp, null +; CHECK: ret i1 %X + %sv = alloca { i32, i32, [124 x i32] } + %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx + %X = icmp eq i32* %cmp, null + ret i1 %X +} +; PR12075 +define i1 @infinite_gep() { + ret i1 1 + +unreachableblock: + %X = getelementptr i32, i32 *%X, i32 1 + %Y = icmp eq i32* %X, null + ret i1 %Y +} + +; It's not valid to fold a comparison of an argument with an alloca, even though +; that's tempting. An argument can't *alias* an alloca, however the aliasing rule +; relies on restrictions against guessing an object's address and dereferencing. +; There are no restrictions against guessing an object's address and comparing. + +define i1 @alloca_argument_compare(i64* %arg) { + %alloc = alloca i64 + %cmp = icmp eq i64* %arg, %alloc + ret i1 %cmp + ; CHECK: alloca_argument_compare + ; CHECK: ret i1 %cmp +} + +; As above, but with the operands reversed. + +define i1 @alloca_argument_compare_swapped(i64* %arg) { + %alloc = alloca i64 + %cmp = icmp eq i64* %alloc, %arg + ret i1 %cmp + ; CHECK: alloca_argument_compare_swapped + ; CHECK: ret i1 %cmp +} + +; Don't assume that a noalias argument isn't equal to a global variable's +; address. This is an example where AliasAnalysis' NoAlias concept is +; different from actual pointer inequality. + +@y = external global i32 +define zeroext i1 @external_compare(i32* noalias %x) { + %cmp = icmp eq i32* %x, @y + ret i1 %cmp + ; CHECK: external_compare + ; CHECK: ret i1 %cmp +} + +define i1 @alloca_gep(i64 %a, i64 %b) { +; CHECK-LABEL: @alloca_gep( +; We can prove this GEP is non-null because it is inbounds and the pointer +; is non-null. + %strs = alloca [1000 x [1001 x i8]], align 16 + %x = getelementptr inbounds [1000 x [1001 x i8]], [1000 x [1001 x i8]]* %strs, i64 0, i64 %a, i64 %b + %cmp = icmp eq i8* %x, null + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +define i1 @alloca_gep_no_null_opt(i64 %a, i64 %b) #0 { +; CHECK-LABEL: @alloca_gep_no_null_opt( +; We can't prove this GEP is non-null. +; CHECK: alloca +; CHECK: getelementptr +; CHECK: icmp +; CHECK: ret + %strs = alloca [1000 x [1001 x i8]], align 16 + %x = getelementptr inbounds [1000 x [1001 x i8]], [1000 x [1001 x i8]]* %strs, i64 0, i64 %a, i64 %b + %cmp = icmp eq i8* %x, null + ret i1 %cmp +} + +define i1 @non_inbounds_gep_compare(i64* %a) { +; CHECK-LABEL: @non_inbounds_gep_compare( +; Equality compares with non-inbounds GEPs can be folded. + %x = getelementptr i64, i64* %a, i64 42 + %y = getelementptr inbounds i64, i64* %x, i64 -42 + %z = getelementptr i64, i64* %a, i64 -42 + %w = getelementptr inbounds i64, i64* %z, i64 42 + %cmp = icmp eq i64* %y, %w + ret i1 %cmp +; CHECK-NEXT: ret i1 true +} + +define i1 @non_inbounds_gep_compare2(i64* %a) { +; CHECK-LABEL: @non_inbounds_gep_compare2( +; Equality compares with non-inbounds GEPs can be folded. + %x = getelementptr i64, i64* %a, i64 4294967297 + %y = getelementptr i64, i64* %a, i64 1 + %cmp = icmp eq i64* %y, %y + ret i1 %cmp +; CHECK-NEXT: ret i1 true +} + +define i1 @compare_always_true_slt(i16 %a) { + %1 = zext i16 %a to i32 + %2 = sub nsw i32 0, %1 + %3 = icmp slt i32 %2, 1 + ret i1 %3 + +; CHECK-LABEL: @compare_always_true_slt +; CHECK-NEXT: ret i1 true +} + +define i1 @compare_always_true_sle(i16 %a) { + %1 = zext i16 %a to i32 + %2 = sub nsw i32 0, %1 + %3 = icmp sle i32 %2, 0 + ret i1 %3 + +; CHECK-LABEL: @compare_always_true_sle +; CHECK-NEXT: ret i1 true +} + +define i1 @compare_always_false_sgt(i16 %a) { + %1 = zext i16 %a to i32 + %2 = sub nsw i32 0, %1 + %3 = icmp sgt i32 %2, 0 + ret i1 %3 + +; CHECK-LABEL: @compare_always_false_sgt +; CHECK-NEXT: ret i1 false +} + +define i1 @compare_always_false_sge(i16 %a) { + %1 = zext i16 %a to i32 + %2 = sub nsw i32 0, %1 + %3 = icmp sge i32 %2, 1 + ret i1 %3 + +; CHECK-LABEL: @compare_always_false_sge +; CHECK-NEXT: ret i1 false +} + +define i1 @compare_always_false_eq(i16 %a) { + %1 = zext i16 %a to i32 + %2 = sub nsw i32 0, %1 + %3 = icmp eq i32 %2, 1 + ret i1 %3 + +; CHECK-LABEL: @compare_always_false_eq +; CHECK-NEXT: ret i1 false +} + +define i1 @compare_always_false_ne(i16 %a) { + %1 = zext i16 %a to i32 + %2 = sub nsw i32 0, %1 + %3 = icmp ne i32 %2, 1 + ret i1 %3 + +; CHECK-LABEL: @compare_always_false_ne +; CHECK-NEXT: ret i1 true +} + +define i1 @lshr_ugt_false(i32 %a) { + %shr = lshr i32 1, %a + %cmp = icmp ugt i32 %shr, 1 + ret i1 %cmp +; CHECK-LABEL: @lshr_ugt_false +; CHECK-NEXT: ret i1 false +} + +define i1 @nonnull_arg(i32* nonnull %i) { + %cmp = icmp eq i32* %i, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_arg +; CHECK: ret i1 false +} + +define i1 @nonnull_arg_no_null_opt(i32* nonnull %i) #0 { + %cmp = icmp eq i32* %i, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_arg_no_null_opt +; CHECK: ret i1 false +} + +define i1 @nonnull_deref_arg(i32* dereferenceable(4) %i) { + %cmp = icmp eq i32* %i, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_deref_arg +; CHECK: ret i1 false +} + +define i1 @nonnull_deref_arg_no_null_opt(i32* dereferenceable(4) %i) #0 { + %cmp = icmp eq i32* %i, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_deref_arg_no_null_opt +; CHECK-NEXT: icmp +; CHECK: ret +} +define i1 @nonnull_deref_as_arg(i32 addrspace(1)* dereferenceable(4) %i) { + %cmp = icmp eq i32 addrspace(1)* %i, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_deref_as_arg +; CHECK: icmp +; CHECK: ret +} + +declare nonnull i32* @returns_nonnull_helper() +define i1 @returns_nonnull() { + %call = call nonnull i32* @returns_nonnull_helper() + %cmp = icmp eq i32* %call, null + ret i1 %cmp +; CHECK-LABEL: @returns_nonnull +; CHECK: ret i1 false +} + +declare dereferenceable(4) i32* @returns_nonnull_deref_helper() +define i1 @returns_nonnull_deref() { + %call = call dereferenceable(4) i32* @returns_nonnull_deref_helper() + %cmp = icmp eq i32* %call, null + ret i1 %cmp +; CHECK-LABEL: @returns_nonnull_deref +; CHECK: ret i1 false +} + +define i1 @returns_nonnull_deref_no_null_opt () #0 { + %call = call dereferenceable(4) i32* @returns_nonnull_deref_helper() + %cmp = icmp eq i32* %call, null + ret i1 %cmp +; CHECK-LABEL: @returns_nonnull_deref_no_null_opt +; CHECK: icmp +; CHECK: ret +} + +declare dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper() +define i1 @returns_nonnull_as_deref() { + %call = call dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper() + %cmp = icmp eq i32 addrspace(1)* %call, null + ret i1 %cmp +; CHECK-LABEL: @returns_nonnull_as_deref +; CHECK: icmp +; CHECK: ret +} + +define i1 @nonnull_load(i32** %addr) { + %ptr = load i32*, i32** %addr, !nonnull !{} + %cmp = icmp eq i32* %ptr, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_load +; CHECK: ret i1 false +} + +define i1 @nonnull_load_as_outer(i32* addrspace(1)* %addr) { + %ptr = load i32*, i32* addrspace(1)* %addr, !nonnull !{} + %cmp = icmp eq i32* %ptr, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_load_as_outer +; CHECK: ret i1 false +} +define i1 @nonnull_load_as_inner(i32 addrspace(1)** %addr) { + %ptr = load i32 addrspace(1)*, i32 addrspace(1)** %addr, !nonnull !{} + %cmp = icmp eq i32 addrspace(1)* %ptr, null + ret i1 %cmp +; CHECK-LABEL: @nonnull_load_as_inner +; CHECK: ret i1 false +} + +; If a bit is known to be zero for A and known to be one for B, +; then A and B cannot be equal. +define i1 @icmp_eq_const(i32 %a) { +; CHECK-LABEL: @icmp_eq_const( +; CHECK-NEXT: ret i1 false +; + %b = mul nsw i32 %a, -2 + %c = icmp eq i32 %b, 1 + ret i1 %c +} + +define <2 x i1> @icmp_eq_const_vec(<2 x i32> %a) { +; CHECK-LABEL: @icmp_eq_const_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2> + %c = icmp eq <2 x i32> %b, <i32 1, i32 1> + ret <2 x i1> %c +} + +define i1 @icmp_ne_const(i32 %a) { +; CHECK-LABEL: @icmp_ne_const( +; CHECK-NEXT: ret i1 true +; + %b = mul nsw i32 %a, -2 + %c = icmp ne i32 %b, 1 + ret i1 %c +} + +define <2 x i1> @icmp_ne_const_vec(<2 x i32> %a) { +; CHECK-LABEL: @icmp_ne_const_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %b = mul nsw <2 x i32> %a, <i32 -2, i32 -2> + %c = icmp ne <2 x i32> %b, <i32 1, i32 1> + ret <2 x i1> %c +} + +define i1 @icmp_sdiv_int_min(i32 %a) { + %div = sdiv i32 -2147483648, %a + %cmp = icmp ne i32 %div, -1073741824 + ret i1 %cmp + +; CHECK-LABEL: @icmp_sdiv_int_min +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 -2147483648, %a +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[DIV]], -1073741824 +; CHECK-NEXT: ret i1 [[CMP]] +} + +define i1 @icmp_sdiv_pr20288(i64 %a) { + %div = sdiv i64 %a, -8589934592 + %cmp = icmp ne i64 %div, 1073741824 + ret i1 %cmp + +; CHECK-LABEL: @icmp_sdiv_pr20288 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 %a, -8589934592 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824 +; CHECK-NEXT: ret i1 [[CMP]] +} + +define i1 @icmp_sdiv_neg1(i64 %a) { + %div = sdiv i64 %a, -1 + %cmp = icmp ne i64 %div, 1073741824 + ret i1 %cmp + +; CHECK-LABEL: @icmp_sdiv_neg1 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 %a, -1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824 +; CHECK-NEXT: ret i1 [[CMP]] +} + +define i1 @icmp_known_bits(i4 %x, i4 %y) { + %and1 = and i4 %y, -7 + %and2 = and i4 %x, -7 + %or1 = or i4 %and1, 2 + %or2 = or i4 %and2, 2 + %add = add i4 %or1, %or2 + %cmp = icmp eq i4 %add, 0 + ret i1 %cmp + +; CHECK-LABEL: @icmp_known_bits +; CHECK-NEXT: ret i1 false +} + +define i1 @icmp_shl_nuw_1(i64 %a) { + %shl = shl nuw i64 1, %a + %cmp = icmp ne i64 %shl, 0 + ret i1 %cmp + +; CHECK-LABEL: @icmp_shl_nuw_1 +; CHECK-NEXT: ret i1 true +} + +define i1 @icmp_shl_1_V_ugt_2147483648(i32 %V) { + %shl = shl i32 1, %V + %cmp = icmp ugt i32 %shl, 2147483648 + ret i1 %cmp + +; CHECK-LABEL: @icmp_shl_1_V_ugt_2147483648( +; CHECK-NEXT: ret i1 false +} + +define i1 @icmp_shl_1_V_ule_2147483648(i32 %V) { + %shl = shl i32 1, %V + %cmp = icmp ule i32 %shl, 2147483648 + ret i1 %cmp + +; CHECK-LABEL: @icmp_shl_1_V_ule_2147483648( +; CHECK-NEXT: ret i1 true +} + +define i1 @icmp_shl_1_V_eq_31(i32 %V) { + %shl = shl i32 1, %V + %cmp = icmp eq i32 %shl, 31 + ret i1 %cmp + +; CHECK-LABEL: @icmp_shl_1_V_eq_31( +; CHECK-NEXT: ret i1 false +} + +define i1 @icmp_shl_1_V_ne_31(i32 %V) { + %shl = shl i32 1, %V + %cmp = icmp ne i32 %shl, 31 + ret i1 %cmp + +; CHECK-LABEL: @icmp_shl_1_V_ne_31( +; CHECK-NEXT: ret i1 true +} + +define i1 @tautological1(i32 %A, i32 %B) { + %C = and i32 %A, %B + %D = icmp ugt i32 %C, %A + ret i1 %D +; CHECK-LABEL: @tautological1( +; CHECK: ret i1 false +} + +define i1 @tautological2(i32 %A, i32 %B) { + %C = and i32 %A, %B + %D = icmp ule i32 %C, %A + ret i1 %D +; CHECK-LABEL: @tautological2( +; CHECK: ret i1 true +} + +define i1 @tautological3(i32 %A, i32 %B) { + %C = or i32 %A, %B + %D = icmp ule i32 %A, %C + ret i1 %D +; CHECK-LABEL: @tautological3( +; CHECK: ret i1 true +} + +define i1 @tautological4(i32 %A, i32 %B) { + %C = or i32 %A, %B + %D = icmp ugt i32 %A, %C + ret i1 %D +; CHECK-LABEL: @tautological4( +; CHECK: ret i1 false +} + +define i1 @tautological5(i32 %A, i32 %B) { + %C = or i32 %A, %B + %D = icmp ult i32 %C, %A + ret i1 %D +; CHECK-LABEL: @tautological5( +; CHECK: ret i1 false +} + +define i1 @tautological6(i32 %A, i32 %B) { + %C = or i32 %A, %B + %D = icmp uge i32 %C, %A + ret i1 %D +; CHECK-LABEL: @tautological6( +; CHECK: ret i1 true +} + +define i1 @tautological7(i32 %A, i32 %B) { + %C = and i32 %A, %B + %D = icmp uge i32 %A, %C + ret i1 %D +; CHECK-LABEL: @tautological7( +; CHECK: ret i1 true +} + +define i1 @tautological8(i32 %A, i32 %B) { + %C = and i32 %A, %B + %D = icmp ult i32 %A, %C + ret i1 %D +; CHECK-LABEL: @tautological8( +; CHECK: ret i1 false +} + +declare void @helper_i1(i1) +; Series of tests for icmp s[lt|ge] (or A, B), A and icmp s[gt|le] A, (or A, B) +define void @icmp_slt_sge_or(i32 %Ax, i32 %Bx) { +; 'p' for positive, 'n' for negative, 'x' for potentially either. +; %D is 'icmp slt (or A, B), A' +; %E is 'icmp sge (or A, B), A' making it the not of %D +; %F is 'icmp sgt A, (or A, B)' making it the same as %D +; %G is 'icmp sle A, (or A, B)' making it the not of %D + %Aneg = or i32 %Ax, 2147483648 + %Apos = and i32 %Ax, 2147483647 + %Bneg = or i32 %Bx, 2147483648 + %Bpos = and i32 %Bx, 2147483647 + + %Cpp = or i32 %Apos, %Bpos + %Dpp = icmp slt i32 %Cpp, %Apos + %Epp = icmp sge i32 %Cpp, %Apos + %Fpp = icmp sgt i32 %Apos, %Cpp + %Gpp = icmp sle i32 %Apos, %Cpp + %Cpx = or i32 %Apos, %Bx + %Dpx = icmp slt i32 %Cpx, %Apos + %Epx = icmp sge i32 %Cpx, %Apos + %Fpx = icmp sgt i32 %Apos, %Cpx + %Gpx = icmp sle i32 %Apos, %Cpx + %Cpn = or i32 %Apos, %Bneg + %Dpn = icmp slt i32 %Cpn, %Apos + %Epn = icmp sge i32 %Cpn, %Apos + %Fpn = icmp sgt i32 %Apos, %Cpn + %Gpn = icmp sle i32 %Apos, %Cpn + + %Cxp = or i32 %Ax, %Bpos + %Dxp = icmp slt i32 %Cxp, %Ax + %Exp = icmp sge i32 %Cxp, %Ax + %Fxp = icmp sgt i32 %Ax, %Cxp + %Gxp = icmp sle i32 %Ax, %Cxp + %Cxx = or i32 %Ax, %Bx + %Dxx = icmp slt i32 %Cxx, %Ax + %Exx = icmp sge i32 %Cxx, %Ax + %Fxx = icmp sgt i32 %Ax, %Cxx + %Gxx = icmp sle i32 %Ax, %Cxx + %Cxn = or i32 %Ax, %Bneg + %Dxn = icmp slt i32 %Cxn, %Ax + %Exn = icmp sge i32 %Cxn, %Ax + %Fxn = icmp sgt i32 %Ax, %Cxn + %Gxn = icmp sle i32 %Ax, %Cxn + + %Cnp = or i32 %Aneg, %Bpos + %Dnp = icmp slt i32 %Cnp, %Aneg + %Enp = icmp sge i32 %Cnp, %Aneg + %Fnp = icmp sgt i32 %Aneg, %Cnp + %Gnp = icmp sle i32 %Aneg, %Cnp + %Cnx = or i32 %Aneg, %Bx + %Dnx = icmp slt i32 %Cnx, %Aneg + %Enx = icmp sge i32 %Cnx, %Aneg + %Fnx = icmp sgt i32 %Aneg, %Cnx + %Gnx = icmp sle i32 %Aneg, %Cnx + %Cnn = or i32 %Aneg, %Bneg + %Dnn = icmp slt i32 %Cnn, %Aneg + %Enn = icmp sge i32 %Cnn, %Aneg + %Fnn = icmp sgt i32 %Aneg, %Cnn + %Gnn = icmp sle i32 %Aneg, %Cnn + + call void @helper_i1(i1 %Dpp) + call void @helper_i1(i1 %Epp) + call void @helper_i1(i1 %Fpp) + call void @helper_i1(i1 %Gpp) + call void @helper_i1(i1 %Dpx) + call void @helper_i1(i1 %Epx) + call void @helper_i1(i1 %Fpx) + call void @helper_i1(i1 %Gpx) + call void @helper_i1(i1 %Dpn) + call void @helper_i1(i1 %Epn) + call void @helper_i1(i1 %Fpn) + call void @helper_i1(i1 %Gpn) + call void @helper_i1(i1 %Dxp) + call void @helper_i1(i1 %Exp) + call void @helper_i1(i1 %Fxp) + call void @helper_i1(i1 %Gxp) + call void @helper_i1(i1 %Dxx) + call void @helper_i1(i1 %Exx) + call void @helper_i1(i1 %Fxx) + call void @helper_i1(i1 %Gxx) + call void @helper_i1(i1 %Dxn) + call void @helper_i1(i1 %Exn) + call void @helper_i1(i1 %Fxn) + call void @helper_i1(i1 %Gxn) + call void @helper_i1(i1 %Dnp) + call void @helper_i1(i1 %Enp) + call void @helper_i1(i1 %Fnp) + call void @helper_i1(i1 %Gnp) + call void @helper_i1(i1 %Dnx) + call void @helper_i1(i1 %Enx) + call void @helper_i1(i1 %Fnx) + call void @helper_i1(i1 %Gnx) + call void @helper_i1(i1 %Dnn) + call void @helper_i1(i1 %Enn) + call void @helper_i1(i1 %Fnn) + call void @helper_i1(i1 %Gnn) +; CHECK-LABEL: @icmp_slt_sge_or +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 %Dpx) +; CHECK: call void @helper_i1(i1 %Epx) +; CHECK: call void @helper_i1(i1 %Fpx) +; CHECK: call void @helper_i1(i1 %Gpx) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 %Dxx) +; CHECK: call void @helper_i1(i1 %Exx) +; CHECK: call void @helper_i1(i1 %Fxx) +; CHECK: call void @helper_i1(i1 %Gxx) +; CHECK: call void @helper_i1(i1 %Dxn) +; CHECK: call void @helper_i1(i1 %Exn) +; CHECK: call void @helper_i1(i1 %Fxn) +; CHECK: call void @helper_i1(i1 %Gxn) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) +; CHECK: call void @helper_i1(i1 false) +; CHECK: call void @helper_i1(i1 true) + ret void +} + +define i1 @constant_fold_inttoptr_null() { +; CHECK-LABEL: @constant_fold_inttoptr_null( +; CHECK-NEXT: ret i1 false +; + %x = icmp eq i32* inttoptr (i64 32 to i32*), null + ret i1 %x +} + +define i1 @constant_fold_null_inttoptr() { +; CHECK-LABEL: @constant_fold_null_inttoptr( +; CHECK-NEXT: ret i1 false +; + %x = icmp eq i32* null, inttoptr (i64 32 to i32*) + ret i1 %x +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/InstSimplify/constantfold-add-nuw-allones-to-allones.ll b/llvm/test/Transforms/InstSimplify/constantfold-add-nuw-allones-to-allones.ll new file mode 100644 index 00000000000..53393c1cf0d --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/constantfold-add-nuw-allones-to-allones.ll @@ -0,0 +1,140 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; %ret = add nuw i8 %x, C +; nuw means no unsigned wrap, from -1 to 0. +; So if C is -1, %x can only be 0, and the result is always -1. + +define i8 @add_nuw (i8 %x) { +; CHECK-LABEL: @add_nuw( +; CHECK-NEXT: ret i8 -1 +; + %ret = add nuw i8 %x, -1 + ; nuw here means that %x can only be 0 + ret i8 %ret +} + +define i8 @add_nuw_nsw (i8 %x) { +; CHECK-LABEL: @add_nuw_nsw( +; CHECK-NEXT: ret i8 -1 +; + %ret = add nuw nsw i8 %x, -1 + ; nuw here means that %x can only be 0 + ret i8 %ret +} + +define i8 @add_nuw_commute (i8 %x) { +; CHECK-LABEL: @add_nuw_commute( +; CHECK-NEXT: ret i8 -1 +; + %ret = add nuw i8 -1, %x ; swapped + ; nuw here means that %x can only be 0 + ret i8 %ret +} + +; ============================================================================ ; +; Positive tests with value range known +; ============================================================================ ; + +declare void @llvm.assume(i1 %cond); + +define i8 @knownbits_allones(i8 %x, i8 %y) { +; CHECK-LABEL: @knownbits_allones( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[Y:%.*]], -2 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = add nuw i8 [[X:%.*]], [[Y]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp slt i8 %y, 254 + tail call void @llvm.assume(i1 %cmp) + %ret = add nuw i8 %x, %y + ret i8 %ret +} + +; ============================================================================ ; +; Vectors +; ============================================================================ ; + +define <2 x i8> @add_vec(<2 x i8> %x) { +; CHECK-LABEL: @add_vec( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1> +; + %ret = add nuw <2 x i8> %x, <i8 -1, i8 -1> + ret <2 x i8> %ret +} + +define <3 x i8> @add_vec_undef(<3 x i8> %x) { +; CHECK-LABEL: @add_vec_undef( +; CHECK-NEXT: ret <3 x i8> <i8 -1, i8 undef, i8 -1> +; + %ret = add nuw <3 x i8> %x, <i8 -1, i8 undef, i8 -1> + ret <3 x i8> %ret +} + +; ============================================================================ ; +; Negative tests. Should not be folded. +; ============================================================================ ; + +define i8 @bad_add (i8 %x) { +; CHECK-LABEL: @bad_add( +; CHECK-NEXT: [[RET:%.*]] = add i8 [[X:%.*]], -1 +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = add i8 %x, -1 ; need nuw + ret i8 %ret +} + +define i8 @bad_add_nsw (i8 %x) { +; CHECK-LABEL: @bad_add_nsw( +; CHECK-NEXT: [[RET:%.*]] = add nsw i8 [[X:%.*]], -1 +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = add nsw i8 %x, -1 ; need nuw + ret i8 %ret +} + +; Second `add` operand is not `-1` constant + +define i8 @bad_add0(i8 %x, i8 %addop2) { +; CHECK-LABEL: @bad_add0( +; CHECK-NEXT: [[RET:%.*]] = add nuw i8 [[X:%.*]], [[ADDOP2:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = add nuw i8 %x, %addop2 + ret i8 %ret +} + +; Bad constant + +define i8 @bad_add1(i8 %x) { +; CHECK-LABEL: @bad_add1( +; CHECK-NEXT: [[RET:%.*]] = add nuw i8 [[X:%.*]], 1 +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = add nuw i8 %x, 1 ; not -1 + ret i8 %ret +} + +define <2 x i8> @bad_add_vec_nonsplat(<2 x i8> %x) { +; CHECK-LABEL: @bad_add_vec_nonsplat( +; CHECK-NEXT: [[RET:%.*]] = add nuw <2 x i8> [[X:%.*]], <i8 -1, i8 1> +; CHECK-NEXT: ret <2 x i8> [[RET]] +; + %ret = add nuw <2 x i8> %x, <i8 -1, i8 1> + ret <2 x i8> %ret +} + +; Bad known bits + +define i8 @bad_knownbits(i8 %x, i8 %y) { +; CHECK-LABEL: @bad_knownbits( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], -3 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = add nuw i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp slt i8 %x, 253 + tail call void @llvm.assume(i1 %cmp) + %ret = add nuw i8 %x, %y + ret i8 %ret +} diff --git a/llvm/test/Transforms/InstSimplify/constantfold-shl-nuw-C-to-C.ll b/llvm/test/Transforms/InstSimplify/constantfold-shl-nuw-C-to-C.ll new file mode 100644 index 00000000000..5103d70c4ea --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/constantfold-shl-nuw-C-to-C.ll @@ -0,0 +1,212 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; %r = shl nuw i8 C, %x +; As per langref: If the nuw keyword is present, then the shift produces +; a poison value if it shifts out any non-zero bits. +; Thus, if the sign bit is set on C, then %x can only be 0, which means that +; %r can only be C. + +define i8 @shl_nuw (i8 %x) { +; CHECK-LABEL: @shl_nuw( +; CHECK-NEXT: ret i8 -1 +; + %ret = shl nuw i8 -1, %x + ; nuw here means that %x can only be 0 + ret i8 %ret +} + +define i8 @shl_nuw_nsw (i8 %x) { +; CHECK-LABEL: @shl_nuw_nsw( +; CHECK-NEXT: ret i8 -1 +; + %ret = shl nuw nsw i8 -1, %x + ; nuw here means that %x can only be 0 + ret i8 %ret +} + +define i8 @shl_128 (i8 %x) { +; CHECK-LABEL: @shl_128( +; CHECK-NEXT: ret i8 -128 +; + %ret = shl nuw i8 128, %x + ; 128 == 1<<7 == just the sign bit is set + ret i8 %ret +} + +; ============================================================================ ; +; Positive tests with value range known +; ============================================================================ ; + +declare void @llvm.assume(i1 %cond); + +define i8 @knownbits_negative(i8 %x, i8 %y) { +; CHECK-LABEL: @knownbits_negative( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp slt i8 %x, 0 + tail call void @llvm.assume(i1 %cmp) + %ret = shl nuw i8 %x, %y + ret i8 %ret +} + +define i8 @knownbits_negativeorzero(i8 %x, i8 %y) { +; CHECK-LABEL: @knownbits_negativeorzero( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 1 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp slt i8 %x, 1 + tail call void @llvm.assume(i1 %cmp) + %ret = shl nuw i8 %x, %y + ret i8 %ret +} + +; ============================================================================ ; +; Vectors +; ============================================================================ ; + +define <2 x i8> @shl_vec(<2 x i8> %x) { +; CHECK-LABEL: @shl_vec( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1> +; + %ret = shl nuw <2 x i8> <i8 -1, i8 -1>, %x + ret <2 x i8> %ret +} + +define <3 x i8> @shl_vec_undef(<3 x i8> %x) { +; CHECK-LABEL: @shl_vec_undef( +; CHECK-NEXT: ret <3 x i8> <i8 -1, i8 undef, i8 -1> +; + %ret = shl nuw <3 x i8> <i8 -1, i8 undef, i8 -1>, %x + ret <3 x i8> %ret +} + +define <2 x i8> @shl_vec_nonsplat(<2 x i8> %x) { +; CHECK-LABEL: @shl_vec_nonsplat( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -2> +; + %ret = shl nuw <2 x i8> <i8 -1, i8 -2>, %x + ret <2 x i8> %ret +} + +; ============================================================================ ; +; Negative tests. Should not be folded. +; ============================================================================ ; + +define i8 @shl_127 (i8 %x) { +; CHECK-LABEL: @shl_127( +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 127, [[X:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = shl nuw i8 127, %x + ; 127 == (1<<7)-1 == all bits except the sign bit are set. + ret i8 %ret +} + +define i8 @bad_shl (i8 %x) { +; CHECK-LABEL: @bad_shl( +; CHECK-NEXT: [[RET:%.*]] = shl i8 -1, [[X:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = shl i8 -1, %x ; need nuw + ret i8 %ret +} + +define i8 @bad_nsw (i8 %x) { +; CHECK-LABEL: @bad_nsw( +; CHECK-NEXT: [[RET:%.*]] = shl nsw i8 -1, [[X:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = shl nsw i8 -1, %x ; need nuw + ret i8 %ret +} + +; First `shl` operand is not `-1` constant + +define i8 @bad_shl0(i8 %shlop1, i8 %x) { +; CHECK-LABEL: @bad_shl0( +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 [[SHLOP1:%.*]], [[X:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = shl nuw i8 %shlop1, %x + ret i8 %ret +} + +; Bad shl nuw constant + +define i8 @bad_shl1(i8 %x) { +; CHECK-LABEL: @bad_shl1( +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 1, [[X:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %ret = shl nuw i8 1, %x ; not -1 + ret i8 %ret +} + +define <2 x i8> @bad_shl_vec_nonsplat(<2 x i8> %x) { +; CHECK-LABEL: @bad_shl_vec_nonsplat( +; CHECK-NEXT: [[RET:%.*]] = shl nuw <2 x i8> <i8 -1, i8 1>, [[X:%.*]] +; CHECK-NEXT: ret <2 x i8> [[RET]] +; + %ret = shl nuw <2 x i8> <i8 -1, i8 1>, %x + ret <2 x i8> %ret +} + +; Bad known bits + +define i8 @bad_knownbits(i8 %x, i8 %y) { +; CHECK-LABEL: @bad_knownbits( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 2 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp slt i8 %x, 2 + tail call void @llvm.assume(i1 %cmp) + %ret = shl nuw i8 %x, %y + ret i8 %ret +} + +define i8 @bad_knownbits_minusoneormore(i8 %x, i8 %y) { +; CHECK-LABEL: @bad_knownbits_minusoneormore( +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -2 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp sgt i8 %x, -2 + tail call void @llvm.assume(i1 %cmp) + %ret = shl nuw i8 %x, %y + ret i8 %ret +} + +define i8 @bad_knownbits_zeroorpositive(i8 %x, i8 %y) { +; CHECK-LABEL: @bad_knownbits_zeroorpositive( +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp sgt i8 %x, -1 + tail call void @llvm.assume(i1 %cmp) + %ret = shl nuw i8 %x, %y + ret i8 %ret +} + +define i8 @bad_knownbits_positive(i8 %x, i8 %y) { +; CHECK-LABEL: @bad_knownbits_positive( +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], 0 +; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[RET:%.*]] = shl nuw i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[RET]] +; + %cmp = icmp sgt i8 %x, 0 + tail call void @llvm.assume(i1 %cmp) + %ret = shl nuw i8 %x, %y + ret i8 %ret +} diff --git a/llvm/test/Transforms/InstSimplify/dead-code-removal.ll b/llvm/test/Transforms/InstSimplify/dead-code-removal.ll new file mode 100644 index 00000000000..e181f3b60d5 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/dead-code-removal.ll @@ -0,0 +1,15 @@ +; RUN: opt -instsimplify -S < %s | FileCheck %s + +define void @foo() nounwind { + br i1 undef, label %1, label %4 + +; <label>:1 ; preds = %1, %0 +; CHECK-NOT: phi +; CHECK-NOT: sub + %2 = phi i32 [ %3, %1 ], [ undef, %0 ] + %3 = sub i32 0, undef + br label %1 + +; <label>:4 ; preds = %0 + ret void +} diff --git a/llvm/test/Transforms/InstSimplify/div.ll b/llvm/test/Transforms/InstSimplify/div.ll new file mode 100644 index 00000000000..a1c0556ae69 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/div.ll @@ -0,0 +1,196 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @zero_dividend(i32 %A) { +; CHECK-LABEL: @zero_dividend( +; CHECK-NEXT: ret i32 0 +; + %B = sdiv i32 0, %A + ret i32 %B +} + +define <2 x i32> @zero_dividend_vector(<2 x i32> %A) { +; CHECK-LABEL: @zero_dividend_vector( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %B = udiv <2 x i32> zeroinitializer, %A + ret <2 x i32> %B +} + +define <2 x i32> @zero_dividend_vector_undef_elt(<2 x i32> %A) { +; CHECK-LABEL: @zero_dividend_vector_undef_elt( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %B = sdiv <2 x i32> <i32 0, i32 undef>, %A + ret <2 x i32> %B +} + +; Division-by-zero is undef. UB in any vector lane means the whole op is undef. + +define <2 x i8> @sdiv_zero_elt_vec_constfold(<2 x i8> %x) { +; CHECK-LABEL: @sdiv_zero_elt_vec_constfold( +; CHECK-NEXT: ret <2 x i8> undef +; + %div = sdiv <2 x i8> <i8 1, i8 2>, <i8 0, i8 -42> + ret <2 x i8> %div +} + +define <2 x i8> @udiv_zero_elt_vec_constfold(<2 x i8> %x) { +; CHECK-LABEL: @udiv_zero_elt_vec_constfold( +; CHECK-NEXT: ret <2 x i8> undef +; + %div = udiv <2 x i8> <i8 1, i8 2>, <i8 42, i8 0> + ret <2 x i8> %div +} + +define <2 x i8> @sdiv_zero_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @sdiv_zero_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %div = sdiv <2 x i8> %x, <i8 -42, i8 0> + ret <2 x i8> %div +} + +define <2 x i8> @udiv_zero_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @udiv_zero_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %div = udiv <2 x i8> %x, <i8 0, i8 42> + ret <2 x i8> %div +} + +define <2 x i8> @sdiv_undef_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @sdiv_undef_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %div = sdiv <2 x i8> %x, <i8 -42, i8 undef> + ret <2 x i8> %div +} + +define <2 x i8> @udiv_undef_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @udiv_undef_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %div = udiv <2 x i8> %x, <i8 undef, i8 42> + ret <2 x i8> %div +} + +; Division-by-zero is undef. UB in any vector lane means the whole op is undef. +; Thus, we can simplify this: if any element of 'y' is 0, we can do anything. +; Therefore, assume that all elements of 'y' must be 1. + +define <2 x i1> @sdiv_bool_vec(<2 x i1> %x, <2 x i1> %y) { +; CHECK-LABEL: @sdiv_bool_vec( +; CHECK-NEXT: ret <2 x i1> [[X:%.*]] +; + %div = sdiv <2 x i1> %x, %y + ret <2 x i1> %div +} + +define <2 x i1> @udiv_bool_vec(<2 x i1> %x, <2 x i1> %y) { +; CHECK-LABEL: @udiv_bool_vec( +; CHECK-NEXT: ret <2 x i1> [[X:%.*]] +; + %div = udiv <2 x i1> %x, %y + ret <2 x i1> %div +} + +define i32 @zext_bool_udiv_divisor(i1 %x, i32 %y) { +; CHECK-LABEL: @zext_bool_udiv_divisor( +; CHECK-NEXT: ret i32 [[Y:%.*]] +; + %ext = zext i1 %x to i32 + %r = udiv i32 %y, %ext + ret i32 %r +} + +define <2 x i32> @zext_bool_sdiv_divisor_vec(<2 x i1> %x, <2 x i32> %y) { +; CHECK-LABEL: @zext_bool_sdiv_divisor_vec( +; CHECK-NEXT: ret <2 x i32> [[Y:%.*]] +; + %ext = zext <2 x i1> %x to <2 x i32> + %r = sdiv <2 x i32> %y, %ext + ret <2 x i32> %r +} + +define i32 @udiv_dividend_known_smaller_than_constant_divisor(i32 %x) { +; CHECK-LABEL: @udiv_dividend_known_smaller_than_constant_divisor( +; CHECK-NEXT: ret i32 0 +; + %and = and i32 %x, 250 + %div = udiv i32 %and, 251 + ret i32 %div +} + +define i32 @not_udiv_dividend_known_smaller_than_constant_divisor(i32 %x) { +; CHECK-LABEL: @not_udiv_dividend_known_smaller_than_constant_divisor( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 251 +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AND]], 251 +; CHECK-NEXT: ret i32 [[DIV]] +; + %and = and i32 %x, 251 + %div = udiv i32 %and, 251 + ret i32 %div +} + +define i32 @udiv_constant_dividend_known_smaller_than_divisor(i32 %x) { +; CHECK-LABEL: @udiv_constant_dividend_known_smaller_than_divisor( +; CHECK-NEXT: ret i32 0 +; + %or = or i32 %x, 251 + %div = udiv i32 250, %or + ret i32 %div +} + +define i32 @not_udiv_constant_dividend_known_smaller_than_divisor(i32 %x) { +; CHECK-LABEL: @not_udiv_constant_dividend_known_smaller_than_divisor( +; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 251 +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 251, [[OR]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %or = or i32 %x, 251 + %div = udiv i32 251, %or + ret i32 %div +} + +; This would require computing known bits on both x and y. Is it worth doing? + +define i32 @udiv_dividend_known_smaller_than_divisor(i32 %x, i32 %y) { +; CHECK-LABEL: @udiv_dividend_known_smaller_than_divisor( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 250 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 251 +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AND]], [[OR]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %and = and i32 %x, 250 + %or = or i32 %y, 251 + %div = udiv i32 %and, %or + ret i32 %div +} + +define i32 @not_udiv_dividend_known_smaller_than_divisor(i32 %x, i32 %y) { +; CHECK-LABEL: @not_udiv_dividend_known_smaller_than_divisor( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 251 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 251 +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AND]], [[OR]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %and = and i32 %x, 251 + %or = or i32 %y, 251 + %div = udiv i32 %and, %or + ret i32 %div +} + +declare i32 @external() + +define i32 @div1() { +; CHECK-LABEL: @div1( +; CHECK-NEXT: [[CALL:%.*]] = call i32 @external(), !range !0 +; CHECK-NEXT: ret i32 0 +; + %call = call i32 @external(), !range !0 + %urem = udiv i32 %call, 3 + ret i32 %urem +} + +!0 = !{i32 0, i32 3} diff --git a/llvm/test/Transforms/InstSimplify/exact-nsw-nuw.ll b/llvm/test/Transforms/InstSimplify/exact-nsw-nuw.ll new file mode 100644 index 00000000000..2cf4405e3c1 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/exact-nsw-nuw.ll @@ -0,0 +1,69 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; PR8862 + +define i32 @shift1(i32 %A, i32 %B) { +; CHECK-LABEL: @shift1( +; CHECK-NEXT: ret i32 %A +; + %C = lshr exact i32 %A, %B + %D = shl nuw i32 %C, %B + ret i32 %D +} + +define i32 @shift2(i32 %A, i32 %B) { +; CHECK-LABEL: @shift2( +; CHECK-NEXT: [[C:%.*]] = lshr i32 %A, %B +; CHECK-NEXT: [[D:%.*]] = shl nuw i32 [[C]], %B +; CHECK-NEXT: ret i32 [[D]] +; + %C = lshr i32 %A, %B + %D = shl nuw i32 %C, %B + ret i32 %D +} + +define i32 @shift3(i32 %A, i32 %B) { +; CHECK-LABEL: @shift3( +; CHECK-NEXT: ret i32 %A +; + %C = ashr exact i32 %A, %B + %D = shl nuw i32 %C, %B + ret i32 %D +} + +define i32 @shift4(i32 %A, i32 %B) { +; CHECK-LABEL: @shift4( +; CHECK-NEXT: ret i32 %A +; + %C = shl nuw i32 %A, %B + %D = lshr i32 %C, %B + ret i32 %D +} + +define i32 @shift5(i32 %A, i32 %B) { +; CHECK-LABEL: @shift5( +; CHECK-NEXT: ret i32 %A +; + %C = shl nsw i32 %A, %B + %D = ashr i32 %C, %B + ret i32 %D +} + +define i32 @div1(i32 %V) { +; CHECK-LABEL: @div1( +; CHECK-NEXT: ret i32 0 +; + %A = udiv i32 %V, -2147483648 + %B = udiv i32 %A, -2147483648 + ret i32 %B +} + +define i32 @div2(i32 %V) { +; CHECK-LABEL: @div2( +; CHECK-NEXT: ret i32 0 +; + %A = sdiv i32 %V, -1 + %B = sdiv i32 %A, -2147483648 + ret i32 %B +} + diff --git a/llvm/test/Transforms/InstSimplify/extract-element.ll b/llvm/test/Transforms/InstSimplify/extract-element.ll new file mode 100644 index 00000000000..ef12a78d1dc --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/extract-element.ll @@ -0,0 +1,56 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; Weird Types + +define i129 @vec_extract_negidx(<3 x i129> %a) { +; CHECK-LABEL: @vec_extract_negidx( +; CHECK-NEXT: ret i129 undef +; + %E1 = extractelement <3 x i129> %a, i129 -1 + ret i129 %E1 +} + +define i129 @vec_extract_out_of_bounds(<3 x i129> %a) { +; CHECK-LABEL: @vec_extract_out_of_bounds( +; CHECK-NEXT: ret i129 undef +; + %E1 = extractelement <3 x i129> %a, i129 3 + ret i129 %E1 +} + +define i129 @vec_extract_out_of_bounds2(<3 x i129> %a) { +; CHECK-LABEL: @vec_extract_out_of_bounds2( +; CHECK-NEXT: ret i129 undef +; + %E1 = extractelement <3 x i129> %a, i129 999999999999999 + ret i129 %E1 +} + + +define i129 @vec_extract_undef_index(<3 x i129> %a) { +; CHECK-LABEL: @vec_extract_undef_index( +; CHECK-NEXT: ret i129 undef +; + %E1 = extractelement <3 x i129> %a, i129 undef + ret i129 %E1 +} + + +define i129 @vec_extract_in_bounds(<3 x i129> %a) { +; CHECK-LABEL: @vec_extract_in_bounds( +; CHECK-NEXT: [[E1:%.*]] = extractelement <3 x i129> [[A:%.*]], i129 2 +; CHECK-NEXT: ret i129 [[E1]] +; + %E1 = extractelement <3 x i129> %a, i129 2 + ret i129 %E1 +} + +define float @extract_element_splat_constant_vector_variable_index(i32 %y) { +; CHECK-LABEL: @extract_element_splat_constant_vector_variable_index( +; CHECK-NEXT: ret float 2.000000e+00 +; + %r = extractelement <4 x float> <float 2.0, float 2.0, float 2.0, float 2.0>, i32 %y + ret float %r +} + diff --git a/llvm/test/Transforms/InstSimplify/fast-math.ll b/llvm/test/Transforms/InstSimplify/fast-math.ll new file mode 100644 index 00000000000..08fb6112e57 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fast-math.ll @@ -0,0 +1,462 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +;; x * 0 ==> 0 when no-nans and no-signed-zero +define float @mul_zero_1(float %a) { +; CHECK-LABEL: @mul_zero_1( +; CHECK-NEXT: ret float 0.000000e+00 +; + %b = fmul nsz nnan float %a, 0.0 + ret float %b +} + +define float @mul_zero_2(float %a) { +; CHECK-LABEL: @mul_zero_2( +; CHECK-NEXT: ret float 0.000000e+00 +; + %b = fmul fast float 0.0, %a + ret float %b +} + +define <2 x float> @mul_zero_nsz_nnan_vec_undef(<2 x float> %a) { +; CHECK-LABEL: @mul_zero_nsz_nnan_vec_undef( +; CHECK-NEXT: ret <2 x float> zeroinitializer +; + %b = fmul nsz nnan <2 x float> %a, <float 0.0, float undef> + ret <2 x float> %b +} + +;; x * 0 =/=> 0 when there could be nans or -0 +define float @no_mul_zero_1(float %a) { +; CHECK-LABEL: @no_mul_zero_1( +; CHECK-NEXT: [[B:%.*]] = fmul nsz float [[A:%.*]], 0.000000e+00 +; CHECK-NEXT: ret float [[B]] +; + %b = fmul nsz float %a, 0.0 + ret float %b +} + +define float @no_mul_zero_2(float %a) { +; CHECK-LABEL: @no_mul_zero_2( +; CHECK-NEXT: [[B:%.*]] = fmul nnan float [[A:%.*]], 0.000000e+00 +; CHECK-NEXT: ret float [[B]] +; + %b = fmul nnan float %a, 0.0 + ret float %b +} + +define float @no_mul_zero_3(float %a) { +; CHECK-LABEL: @no_mul_zero_3( +; CHECK-NEXT: [[B:%.*]] = fmul float [[A:%.*]], 0.000000e+00 +; CHECK-NEXT: ret float [[B]] +; + %b = fmul float %a, 0.0 + ret float %b +} + +; -X + X --> 0.0 (with nnan on the fadd) + +define float @fadd_fnegx(float %x) { +; CHECK-LABEL: @fadd_fnegx( +; CHECK-NEXT: ret float 0.000000e+00 +; + %negx = fsub float -0.0, %x + %r = fadd nnan float %negx, %x + ret float %r +} + +; X + -X --> 0.0 (with nnan on the fadd) + +define <2 x float> @fadd_fnegx_commute_vec(<2 x float> %x) { +; CHECK-LABEL: @fadd_fnegx_commute_vec( +; CHECK-NEXT: ret <2 x float> zeroinitializer +; + %negx = fsub <2 x float> <float -0.0, float -0.0>, %x + %r = fadd nnan <2 x float> %x, %negx + ret <2 x float> %r +} + +define <2 x float> @fadd_fnegx_commute_vec_undef(<2 x float> %x) { +; CHECK-LABEL: @fadd_fnegx_commute_vec_undef( +; CHECK-NEXT: ret <2 x float> zeroinitializer +; + %negx = fsub <2 x float> <float undef, float -0.0>, %x + %r = fadd nnan <2 x float> %x, %negx + ret <2 x float> %r +} + +; https://bugs.llvm.org/show_bug.cgi?id=26958 +; https://bugs.llvm.org/show_bug.cgi?id=27151 + +define float @fadd_fneg_nan(float %x) { +; CHECK-LABEL: @fadd_fneg_nan( +; CHECK-NEXT: [[T:%.*]] = fsub nnan float -0.000000e+00, [[X:%.*]] +; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = fadd ninf float [[T]], [[X]] +; CHECK-NEXT: ret float [[COULD_BE_NAN]] +; + %t = fsub nnan float -0.0, %x + %could_be_nan = fadd ninf float %t, %x + ret float %could_be_nan +} + +define float @fadd_fneg_nan_commute(float %x) { +; CHECK-LABEL: @fadd_fneg_nan_commute( +; CHECK-NEXT: [[T:%.*]] = fsub nnan ninf float -0.000000e+00, [[X:%.*]] +; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = fadd float [[X]], [[T]] +; CHECK-NEXT: ret float [[COULD_BE_NAN]] +; + %t = fsub nnan ninf float -0.0, %x + %could_be_nan = fadd float %x, %t + ret float %could_be_nan +} + +; X + (0.0 - X) --> 0.0 (with nnan on the fadd) + +define float @fadd_fsub_nnan_ninf(float %x) { +; CHECK-LABEL: @fadd_fsub_nnan_ninf( +; CHECK-NEXT: ret float 0.000000e+00 +; + %sub = fsub float 0.0, %x + %zero = fadd nnan ninf float %x, %sub + ret float %zero +} + +; (0.0 - X) + X --> 0.0 (with nnan on the fadd) + +define <2 x float> @fadd_fsub_nnan_ninf_commute_vec(<2 x float> %x) { +; CHECK-LABEL: @fadd_fsub_nnan_ninf_commute_vec( +; CHECK-NEXT: ret <2 x float> zeroinitializer +; + %sub = fsub <2 x float> zeroinitializer, %x + %zero = fadd nnan ninf <2 x float> %sub, %x + ret <2 x float> %zero +} + +; 'ninf' is not required because 'nnan' allows us to assume +; that X is not INF or -INF (adding opposite INFs would be NaN). + +define float @fadd_fsub_nnan(float %x) { +; CHECK-LABEL: @fadd_fsub_nnan( +; CHECK-NEXT: ret float 0.000000e+00 +; + %sub = fsub float 0.0, %x + %zero = fadd nnan float %sub, %x + ret float %zero +} + +; fsub nnan x, x ==> 0.0 +define float @fsub_x_x(float %a) { +; CHECK-LABEL: @fsub_x_x( +; CHECK-NEXT: [[NO_ZERO1:%.*]] = fsub ninf float [[A:%.*]], [[A]] +; CHECK-NEXT: [[NO_ZERO2:%.*]] = fsub float [[A]], [[A]] +; CHECK-NEXT: [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]] +; CHECK-NEXT: ret float [[NO_ZERO]] +; +; X - X ==> 0 + %zero1 = fsub nnan float %a, %a + +; Dont fold + %no_zero1 = fsub ninf float %a, %a + %no_zero2 = fsub float %a, %a + %no_zero = fadd float %no_zero1, %no_zero2 + +; Should get folded + %ret = fadd nsz float %no_zero, %zero1 + + ret float %ret +} + +; fsub nsz 0.0, (fsub 0.0, X) ==> X +define float @fsub_0_0_x(float %a) { +; CHECK-LABEL: @fsub_0_0_x( +; CHECK-NEXT: ret float [[A:%.*]] +; + %t1 = fsub float 0.0, %a + %ret = fsub nsz float 0.0, %t1 + ret float %ret +} + +define <2 x float> @fsub_0_0_x_vec_undef1(<2 x float> %a) { +; CHECK-LABEL: @fsub_0_0_x_vec_undef1( +; CHECK-NEXT: ret <2 x float> [[A:%.*]] +; + %t1 = fsub <2 x float> <float 0.0, float undef>, %a + %ret = fsub nsz <2 x float> zeroinitializer, %t1 + ret <2 x float> %ret +} + +define <2 x float> @fsub_0_0_x_vec_undef2(<2 x float> %a) { +; CHECK-LABEL: @fsub_0_0_x_vec_undef2( +; CHECK-NEXT: ret <2 x float> [[A:%.*]] +; + %t1 = fsub <2 x float> zeroinitializer, %a + %ret = fsub nsz <2 x float> <float undef, float -0.0>, %t1 + ret <2 x float> %ret +} + +; fadd nsz X, 0 ==> X + +define <2 x float> @fadd_zero_nsz_vec(<2 x float> %x) { +; CHECK-LABEL: @fadd_zero_nsz_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = fadd nsz <2 x float> %x, zeroinitializer + ret <2 x float> %r +} + +define <2 x float> @fadd_zero_nsz_vec_undef(<2 x float> %x) { +; CHECK-LABEL: @fadd_zero_nsz_vec_undef( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = fadd nsz <2 x float> %x, <float 0.0, float undef> + ret <2 x float> %r +} + +define float @nofold_fadd_x_0(float %a) { +; CHECK-LABEL: @nofold_fadd_x_0( +; CHECK-NEXT: [[NO_ZERO1:%.*]] = fadd ninf float [[A:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NO_ZERO2:%.*]] = fadd nnan float [[A]], 0.000000e+00 +; CHECK-NEXT: [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]] +; CHECK-NEXT: ret float [[NO_ZERO]] +; +; Dont fold + %no_zero1 = fadd ninf float %a, 0.0 + %no_zero2 = fadd nnan float %a, 0.0 + %no_zero = fadd float %no_zero1, %no_zero2 + ret float %no_zero +} + +define float @fold_fadd_nsz_x_0(float %a) { +; CHECK-LABEL: @fold_fadd_nsz_x_0( +; CHECK-NEXT: ret float [[A:%.*]] +; + %add = fadd nsz float %a, 0.0 + ret float %add +} + +define float @fold_fadd_cannot_be_neg0_nsz_src_x_0(float %a, float %b) { +; CHECK-LABEL: @fold_fadd_cannot_be_neg0_nsz_src_x_0( +; CHECK-NEXT: [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: ret float [[NSZ]] +; + %nsz = fmul nsz float %a, %b + %add = fadd float %nsz, 0.0 + ret float %add +} + +define float @fold_fadd_cannot_be_neg0_fabs_src_x_0(float %a) { +; CHECK-LABEL: @fold_fadd_cannot_be_neg0_fabs_src_x_0( +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) +; CHECK-NEXT: ret float [[FABS]] +; + %fabs = call float @llvm.fabs.f32(float %a) + %add = fadd float %fabs, 0.0 + ret float %add +} + +define float @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(float %a, float %b) { +; CHECK-LABEL: @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0( +; CHECK-NEXT: [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.sqrt.f32(float [[NSZ]]) +; CHECK-NEXT: ret float [[SQRT]] +; + %nsz = fmul nsz float %a, %b + %sqrt = call float @llvm.sqrt.f32(float %nsz) + %add = fadd float %sqrt, 0.0 + ret float %add +} + +define float @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(float %a, float %b) { +; CHECK-LABEL: @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0( +; CHECK-NEXT: [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSZ]]) +; CHECK-NEXT: ret float [[CANON]] +; + %nsz = fmul nsz float %a, %b + %canon = call float @llvm.canonicalize.f32(float %nsz) + %add = fadd float %canon, 0.0 + ret float %add +} + +; fdiv nsz nnan 0, X ==> 0 +; 0 / X -> 0 + +define double @fdiv_zero_by_x(double %x) { +; CHECK-LABEL: @fdiv_zero_by_x( +; CHECK-NEXT: ret double 0.000000e+00 +; + %r = fdiv nnan nsz double 0.0, %x + ret double %r +} + +define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) { +; CHECK-LABEL: @fdiv_zero_by_x_vec_undef( +; CHECK-NEXT: ret <2 x double> zeroinitializer +; + %r = fdiv nnan nsz <2 x double> <double 0.0, double undef>, %x + ret <2 x double> %r +} + +; 0 % X -> 0 +; nsz is not necessary - frem result always has the sign of the dividend + +define double @frem_zero_by_x(double %x) { +; CHECK-LABEL: @frem_zero_by_x( +; CHECK-NEXT: ret double 0.000000e+00 +; + %r = frem nnan double 0.0, %x + ret double %r +} + +define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) { +; CHECK-LABEL: @frem_poszero_by_x_vec_undef( +; CHECK-NEXT: ret <2 x double> zeroinitializer +; + %r = frem nnan <2 x double> <double 0.0, double undef>, %x + ret <2 x double> %r +} + +; -0 % X -> -0 +; nsz is not necessary - frem result always has the sign of the dividend + +define double @frem_negzero_by_x(double %x) { +; CHECK-LABEL: @frem_negzero_by_x( +; CHECK-NEXT: ret double -0.000000e+00 +; + %r = frem nnan double -0.0, %x + ret double %r +} + +define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) { +; CHECK-LABEL: @frem_negzero_by_x_vec_undef( +; CHECK-NEXT: ret <2 x double> <double -0.000000e+00, double -0.000000e+00> +; + %r = frem nnan <2 x double> <double undef, double -0.0>, %x + ret <2 x double> %r +} + +define float @fdiv_self(float %f) { +; CHECK-LABEL: @fdiv_self( +; CHECK-NEXT: ret float 1.000000e+00 +; + %div = fdiv nnan float %f, %f + ret float %div +} + +define float @fdiv_self_invalid(float %f) { +; CHECK-LABEL: @fdiv_self_invalid( +; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[F:%.*]], [[F]] +; CHECK-NEXT: ret float [[DIV]] +; + %div = fdiv float %f, %f + ret float %div +} + +define float @fdiv_neg1(float %f) { +; CHECK-LABEL: @fdiv_neg1( +; CHECK-NEXT: ret float -1.000000e+00 +; + %neg = fsub fast float -0.000000e+00, %f + %div = fdiv nnan float %neg, %f + ret float %div +} + +define float @fdiv_neg2(float %f) { +; CHECK-LABEL: @fdiv_neg2( +; CHECK-NEXT: ret float -1.000000e+00 +; + %neg = fsub fast float 0.000000e+00, %f + %div = fdiv nnan float %neg, %f + ret float %div +} + +define float @fdiv_neg_invalid(float %f) { +; CHECK-LABEL: @fdiv_neg_invalid( +; CHECK-NEXT: [[NEG:%.*]] = fsub fast float -0.000000e+00, [[F:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[NEG]], [[F]] +; CHECK-NEXT: ret float [[DIV]] +; + %neg = fsub fast float -0.000000e+00, %f + %div = fdiv float %neg, %f + ret float %div +} + +define float @fdiv_neg_swapped1(float %f) { +; CHECK-LABEL: @fdiv_neg_swapped1( +; CHECK-NEXT: ret float -1.000000e+00 +; + %neg = fsub float -0.000000e+00, %f + %div = fdiv nnan float %f, %neg + ret float %div +} + +define float @fdiv_neg_swapped2(float %f) { +; CHECK-LABEL: @fdiv_neg_swapped2( +; CHECK-NEXT: ret float -1.000000e+00 +; + %neg = fsub float 0.000000e+00, %f + %div = fdiv nnan float %f, %neg + ret float %div +} + +define <2 x float> @fdiv_neg_vec_undef_elt(<2 x float> %f) { +; CHECK-LABEL: @fdiv_neg_vec_undef_elt( +; CHECK-NEXT: ret <2 x float> <float -1.000000e+00, float -1.000000e+00> +; + %neg = fsub <2 x float> <float 0.0, float undef>, %f + %div = fdiv nnan <2 x float> %f, %neg + ret <2 x float> %div +} + +; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126 +; With loose math, sqrt(X) * sqrt(X) is just X. + +declare double @llvm.sqrt.f64(double) + +define double @sqrt_squared(double %f) { +; CHECK-LABEL: @sqrt_squared( +; CHECK-NEXT: ret double [[F:%.*]] +; + %sqrt = call double @llvm.sqrt.f64(double %f) + %mul = fmul reassoc nnan nsz double %sqrt, %sqrt + ret double %mul +} + +; Negative tests for the above transform: we need all 3 of those flags. + +define double @sqrt_squared_not_fast_enough1(double %f) { +; CHECK-LABEL: @sqrt_squared_not_fast_enough1( +; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]]) +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan nsz double [[SQRT]], [[SQRT]] +; CHECK-NEXT: ret double [[MUL]] +; + %sqrt = call double @llvm.sqrt.f64(double %f) + %mul = fmul nnan nsz double %sqrt, %sqrt + ret double %mul +} + +define double @sqrt_squared_not_fast_enough2(double %f) { +; CHECK-LABEL: @sqrt_squared_not_fast_enough2( +; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]]) +; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc nnan double [[SQRT]], [[SQRT]] +; CHECK-NEXT: ret double [[MUL]] +; + %sqrt = call double @llvm.sqrt.f64(double %f) + %mul = fmul reassoc nnan double %sqrt, %sqrt + ret double %mul +} + +define double @sqrt_squared_not_fast_enough3(double %f) { +; CHECK-LABEL: @sqrt_squared_not_fast_enough3( +; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]]) +; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc nsz double [[SQRT]], [[SQRT]] +; CHECK-NEXT: ret double [[MUL]] +; + %sqrt = call double @llvm.sqrt.f64(double %f) + %mul = fmul reassoc nsz double %sqrt, %sqrt + ret double %mul +} + +declare float @llvm.fabs.f32(float) +declare float @llvm.sqrt.f32(float) +declare float @llvm.canonicalize.f32(float) diff --git a/llvm/test/Transforms/InstSimplify/fcmp-select.ll b/llvm/test/Transforms/InstSimplify/fcmp-select.ll new file mode 100644 index 00000000000..eae885c8471 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fcmp-select.ll @@ -0,0 +1,94 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; X == 42.0 ? X : 42.0 --> 42.0 + +define double @oeq(double %x) { +; CHECK-LABEL: @oeq( +; CHECK-NEXT: ret double 4.200000e+01 +; + %cmp = fcmp oeq double %x, 42.0 + %cond = select i1 %cmp, double %x, double 42.0 + ret double %cond +} + +; X == 42.0 ? 42.0 : X --> X + +define float @oeq_swapped(float %x) { +; CHECK-LABEL: @oeq_swapped( +; CHECK-NEXT: ret float [[X:%.*]] +; + %cmp = fcmp oeq float %x, 42.0 + %cond = select i1 %cmp, float 42.0, float %x + ret float %cond +} + +; x != y ? x : y -> x if it's the right kind of != and at least +; one of x and y is not negative zero. + +; X != 42.0 ? X : 42.0 --> X + +define double @une(double %x) { +; CHECK-LABEL: @une( +; CHECK-NEXT: ret double [[X:%.*]] +; + %cmp = fcmp une double %x, 42.0 + %cond = select i1 %cmp, double %x, double 42.0 + ret double %cond +} + +; X != 42.0 ? 42.0 : X --> 42.0 + +define double @une_swapped(double %x) { +; CHECK-LABEL: @une_swapped( +; CHECK-NEXT: ret double 4.200000e+01 +; + %cmp = fcmp une double %x, 42.0 + %cond = select i1 %cmp, double 42.0, double %x + ret double %cond +} + +define double @une_could_be_negzero(double %x, double %y) { +; CHECK-LABEL: @une_could_be_negzero( +; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], double [[X]], double [[Y]] +; CHECK-NEXT: ret double [[COND]] +; + %cmp = fcmp une double %x, %y + %cond = select i1 %cmp, double %x, double %y + ret double %cond +} + +define double @une_swapped_could_be_negzero(double %x, double %y) { +; CHECK-LABEL: @une_swapped_could_be_negzero( +; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], double [[Y]], double [[X]] +; CHECK-NEXT: ret double [[COND]] +; + %cmp = fcmp une double %x, %y + %cond = select i1 %cmp, double %y, double %x + ret double %cond +} + +define double @one(double %x) { +; CHECK-LABEL: @one( +; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[X:%.*]], -1.000000e+00 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], double [[X]], double -1.000000e+00 +; CHECK-NEXT: ret double [[COND]] +; + %cmp = fcmp one double %x, -1.0 + %cond = select i1 %cmp, double %x, double -1.0 + ret double %cond +} + +define double @one_swapped(double %x) { +; CHECK-LABEL: @one_swapped( +; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[X:%.*]], -1.000000e+00 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], double -1.000000e+00, double [[X]] +; CHECK-NEXT: ret double [[COND]] +; + %cmp = fcmp one double %x, -1.0 + %cond = select i1 %cmp, double -1.0, double %x + ret double %cond +} + diff --git a/llvm/test/Transforms/InstSimplify/fdiv.ll b/llvm/test/Transforms/InstSimplify/fdiv.ll new file mode 100644 index 00000000000..b245c2e4359 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fdiv.ll @@ -0,0 +1,52 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define float @fdiv_constant_fold() { +; CHECK-LABEL: @fdiv_constant_fold( +; CHECK-NEXT: ret float 1.500000e+00 +; + %f = fdiv float 3.0, 2.0 + ret float %f +} + +define float @frem_constant_fold() { +; CHECK-LABEL: @frem_constant_fold( +; CHECK-NEXT: ret float 1.000000e+00 +; + %f = frem float 3.0, 2.0 + ret float %f +} + +define double @fmul_fdiv_common_operand(double %x, double %y) { +; CHECK-LABEL: @fmul_fdiv_common_operand( +; CHECK-NEXT: ret double %x +; + %m = fmul double %x, %y + %d = fdiv reassoc nnan double %m, %y + ret double %d +} + +; Negative test - the fdiv must be reassociative and not allow NaNs. + +define double @fmul_fdiv_common_operand_too_strict(double %x, double %y) { +; CHECK-LABEL: @fmul_fdiv_common_operand_too_strict( +; CHECK-NEXT: [[M:%.*]] = fmul fast double %x, %y +; CHECK-NEXT: [[D:%.*]] = fdiv reassoc double [[M]], %y +; CHECK-NEXT: ret double [[D]] +; + %m = fmul fast double %x, %y + %d = fdiv reassoc double %m, %y + ret double %d +} + +; Commute the fmul operands. Use a vector type to verify that works too. + +define <2 x float> @fmul_fdiv_common_operand_commute_vec(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @fmul_fdiv_common_operand_commute_vec( +; CHECK-NEXT: ret <2 x float> %x +; + %m = fmul <2 x float> %y, %x + %d = fdiv fast <2 x float> %m, %y + ret <2 x float> %d +} + diff --git a/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll new file mode 100644 index 00000000000..acc24d9ba60 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll @@ -0,0 +1,1269 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define <2 x float> @fsub_negzero_vec_undef_elts(<2 x float> %x) { +; CHECK-LABEL: @fsub_negzero_vec_undef_elts( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = fsub nsz <2 x float> %x, <float undef, float -0.0> + ret <2 x float> %r +} + +; fsub -0.0, (fsub -0.0, X) ==> X +define float @fsub_-0_-0_x(float %a) { +; CHECK-LABEL: @fsub_-0_-0_x( +; CHECK-NEXT: ret float [[A:%.*]] +; + %t1 = fsub float -0.0, %a + %ret = fsub float -0.0, %t1 + ret float %ret +} + +define <2 x float> @fsub_-0_-0_x_vec(<2 x float> %a) { +; CHECK-LABEL: @fsub_-0_-0_x_vec( +; CHECK-NEXT: ret <2 x float> [[A:%.*]] +; + %t1 = fsub <2 x float> <float -0.0, float -0.0>, %a + %ret = fsub <2 x float> <float -0.0, float -0.0>, %t1 + ret <2 x float> %ret +} + +define <2 x float> @fsub_-0_-0_x_vec_undef_elts(<2 x float> %a) { +; CHECK-LABEL: @fsub_-0_-0_x_vec_undef_elts( +; CHECK-NEXT: ret <2 x float> [[A:%.*]] +; + %t1 = fsub <2 x float> <float undef, float -0.0>, %a + %ret = fsub <2 x float> <float -0.0, float undef>, %t1 + ret <2 x float> %ret +} + +; fsub 0.0, (fsub -0.0, X) != X +define float @fsub_0_-0_x(float %a) { +; CHECK-LABEL: @fsub_0_-0_x( +; CHECK-NEXT: [[T1:%.*]] = fsub float 0.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[RET:%.*]] = fsub float -0.000000e+00, [[T1]] +; CHECK-NEXT: ret float [[RET]] +; + %t1 = fsub float 0.0, %a + %ret = fsub float -0.0, %t1 + ret float %ret +} + +; fsub -0.0, (fsub 0.0, X) != X +define float @fsub_-0_0_x(float %a) { +; CHECK-LABEL: @fsub_-0_0_x( +; CHECK-NEXT: [[T1:%.*]] = fsub float -0.000000e+00, [[A:%.*]] +; CHECK-NEXT: [[RET:%.*]] = fsub float 0.000000e+00, [[T1]] +; CHECK-NEXT: ret float [[RET]] +; + %t1 = fsub float -0.0, %a + %ret = fsub float 0.0, %t1 + ret float %ret +} + +; fsub X, 0 ==> X +define float @fsub_x_0(float %x) { +; CHECK-LABEL: @fsub_x_0( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = fsub float %x, 0.0 + ret float %r +} + +define <2 x float> @fsub_x_0_vec_undef(<2 x float> %x) { +; CHECK-LABEL: @fsub_x_0_vec_undef( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = fsub <2 x float> %x, <float undef, float 0.0> + ret <2 x float> %r +} + +; fadd X, -0 ==> X +define float @fadd_x_n0(float %a) { +; CHECK-LABEL: @fadd_x_n0( +; CHECK-NEXT: ret float [[A:%.*]] +; + %ret = fadd float %a, -0.0 + ret float %ret +} + +define <2 x float> @fadd_x_n0_vec_undef_elt(<2 x float> %a) { +; CHECK-LABEL: @fadd_x_n0_vec_undef_elt( +; CHECK-NEXT: ret <2 x float> [[A:%.*]] +; + %ret = fadd <2 x float> %a, <float -0.0, float undef> + ret <2 x float> %ret +} + +; fmul X, 1.0 ==> X +define double @fmul_X_1(double %a) { +; CHECK-LABEL: @fmul_X_1( +; CHECK-NEXT: ret double [[A:%.*]] +; + %b = fmul double 1.0, %a + ret double %b +} + +; PR2642 +define <4 x float> @fmul_X_1_vec(<4 x float> %x) { +; CHECK-LABEL: @fmul_X_1_vec( +; CHECK-NEXT: ret <4 x float> [[X:%.*]] +; + %m = fmul <4 x float> %x, <float 1.0, float 1.0, float 1.0, float 1.0> + ret <4 x float> %m +} + +; fdiv X, 1.0 ==> X +define float @fdiv_x_1(float %a) { +; CHECK-LABEL: @fdiv_x_1( +; CHECK-NEXT: ret float [[A:%.*]] +; + %ret = fdiv float %a, 1.0 + ret float %ret +} + +; We can't optimize away the fadd in this test because the input +; value to the function and subsequently to the fadd may be -0.0. +; In that one special case, the result of the fadd should be +0.0 +; rather than the first parameter of the fadd. + +; Fragile test warning: We need 6 sqrt calls to trigger the bug +; because the internal logic has a magic recursion limit of 6. +; This is presented without any explanation or ability to customize. + +declare float @sqrtf(float) + +define float @PR22688(float %x) { +; CHECK-LABEL: @PR22688( +; CHECK-NEXT: [[TMP1:%.*]] = call float @sqrtf(float [[X:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call float @sqrtf(float [[TMP1]]) +; CHECK-NEXT: [[TMP3:%.*]] = call float @sqrtf(float [[TMP2]]) +; CHECK-NEXT: [[TMP4:%.*]] = call float @sqrtf(float [[TMP3]]) +; CHECK-NEXT: [[TMP5:%.*]] = call float @sqrtf(float [[TMP4]]) +; CHECK-NEXT: [[TMP6:%.*]] = call float @sqrtf(float [[TMP5]]) +; CHECK-NEXT: [[TMP7:%.*]] = fadd float [[TMP6]], 0.000000e+00 +; CHECK-NEXT: ret float [[TMP7]] +; + %1 = call float @sqrtf(float %x) + %2 = call float @sqrtf(float %1) + %3 = call float @sqrtf(float %2) + %4 = call float @sqrtf(float %3) + %5 = call float @sqrtf(float %4) + %6 = call float @sqrtf(float %5) + %7 = fadd float %6, 0.0 + ret float %7 +} + +declare float @llvm.fabs.f32(float) +declare <2 x float> @llvm.fabs.v2f32(<2 x float>) +declare float @llvm.sqrt.f32(float) + +define float @fabs_select_positive_constants(i32 %c) { +; CHECK-LABEL: @fabs_select_positive_constants( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00 +; CHECK-NEXT: ret float [[SELECT]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 1.0, float 2.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_positive_constants_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_positive_constants_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x float> <float 2.000000e+00, float 2.000000e+00> +; CHECK-NEXT: ret <2 x float> [[SELECT]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 1.0, float 1.0>, <2 x float> <float 2.0, float 2.0> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_constant_variable(i32 %c, float %x) { +; CHECK-LABEL: @fabs_select_constant_variable( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float 1.000000e+00, float [[X:%.*]] +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 1.0, float %x + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_constant_variable_vector(i32 %c, <2 x float> %x) { +; CHECK-LABEL: @fabs_select_constant_variable_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x float> [[X:%.*]] +; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: ret <2 x float> [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 1.0, float 1.0>, <2 x float> %x + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_neg0_pos0(i32 %c) { +; CHECK-LABEL: @fabs_select_neg0_pos0( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float -0.000000e+00, float 0.000000e+00 +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float -0.0, float 0.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_neg0_pos0_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_neg0_pos0_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> zeroinitializer +; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: ret <2 x float> [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float -0.0, float -0.0>, <2 x float> <float 0.0, float 0.0> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_neg0_neg1(i32 %c) { +; CHECK-LABEL: @fabs_select_neg0_neg1( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float -0.000000e+00, float -1.000000e+00 +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float -0.0, float -1.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_neg0_neg1_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_neg0_neg1_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> <float -1.000000e+00, float -1.000000e+00> +; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: ret <2 x float> [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float -0.0, float -0.0>, <2 x float> <float -1.0, float -1.0> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_nan_nan(i32 %c) { +; CHECK-LABEL: @fabs_select_nan_nan( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float 0x7FF8000000000000, float 0x7FF8000100000000 +; CHECK-NEXT: ret float [[SELECT]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0x7FF8000000000000, float 0x7FF8000100000000 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_nan_nan_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_nan_nan_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000>, <2 x float> <float 0x7FF8000100000000, float 0x7FF8000100000000> +; CHECK-NEXT: ret <2 x float> [[SELECT]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000>, <2 x float> <float 0x7FF8000100000000, float 0x7FF8000100000000> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_negnan_nan(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_nan( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float 0xFFF8000000000000, float 0x7FF8000000000000 +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float 0x7FF8000000000000 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_negnan_nan_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_nan_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000> +; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: ret <2 x float> [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_negnan_negnan(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_negnan( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float 0xFFF8000000000000, float 0x7FF8000100000000 +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float 0x7FF8000100000000 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_negnan_negnan_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_negnan_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> <float 0x7FF8000100000000, float 0x7FF8000100000000> +; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: ret <2 x float> [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> <float 0x7FF8000100000000, float 0x7FF8000100000000> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_negnan_negzero(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_negzero( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float 0xFFF8000000000000, float -0.000000e+00 +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float -0.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_negnan_negzero_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_negzero_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> <float -0.000000e+00, float -0.000000e+00> +; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: ret <2 x float> [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> <float -0.0, float -0.0> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +define float @fabs_select_negnan_zero(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_zero( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float 0xFFF8000000000000, float 0.000000e+00 +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, float 0xFFF8000000000000, float 0.0 + %fabs = call float @llvm.fabs.f32(float %select) + ret float %fabs +} + +define <2 x float> @fabs_select_negnan_zero_vector(i32 %c) { +; CHECK-LABEL: @fabs_select_negnan_zero_vector( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> zeroinitializer +; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[SELECT]]) +; CHECK-NEXT: ret <2 x float> [[FABS]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 0xFFF8000000000000, float 0xFFF8000000000000>, <2 x float> <float 0.0, float 0.0> + %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %select) + ret <2 x float> %fabs +} + +; The fabs can't be eliminated because llvm.sqrt.f32 may return -0 or NaN with +; an arbitrary sign bit. +define float @fabs_sqrt(float %a) { +; CHECK-LABEL: @fabs_sqrt( +; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.sqrt.f32(float [[A:%.*]]) +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %sqrt = call float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; The fabs can't be eliminated because the nnan sqrt may still return -0. +define float @fabs_sqrt_nnan(float %a) { +; CHECK-LABEL: @fabs_sqrt_nnan( +; CHECK-NEXT: [[SQRT:%.*]] = call nnan float @llvm.sqrt.f32(float [[A:%.*]]) +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %sqrt = call nnan float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; The fabs can't be eliminated because the nsz sqrt may still return NaN. +define float @fabs_sqrt_nsz(float %a) { +; CHECK-LABEL: @fabs_sqrt_nsz( +; CHECK-NEXT: [[SQRT:%.*]] = call nsz float @llvm.sqrt.f32(float [[A:%.*]]) +; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) +; CHECK-NEXT: ret float [[FABS]] +; + %sqrt = call nsz float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; The fabs can be eliminated because we're nsz and nnan. +define float @fabs_sqrt_nnan_nsz(float %a) { +; CHECK-LABEL: @fabs_sqrt_nnan_nsz( +; CHECK-NEXT: [[SQRT:%.*]] = call nnan nsz float @llvm.sqrt.f32(float [[A:%.*]]) +; CHECK-NEXT: ret float [[SQRT]] +; + %sqrt = call nnan nsz float @llvm.sqrt.f32(float %a) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +; The second fabs can be eliminated because the operand to sqrt cannot be -0. +define float @fabs_sqrt_nnan_fabs(float %a) { +; CHECK-LABEL: @fabs_sqrt_nnan_fabs( +; CHECK-NEXT: [[B:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) +; CHECK-NEXT: [[SQRT:%.*]] = call nnan float @llvm.sqrt.f32(float [[B]]) +; CHECK-NEXT: ret float [[SQRT]] +; + %b = call float @llvm.fabs.f32(float %a) + %sqrt = call nnan float @llvm.sqrt.f32(float %b) + %fabs = call float @llvm.fabs.f32(float %sqrt) + ret float %fabs +} + +define float @fabs_select_positive_constants_vector_extract(i32 %c) { +; CHECK-LABEL: @fabs_select_positive_constants_vector_extract( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], <2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x float> <float 2.000000e+00, float 2.000000e+00> +; CHECK-NEXT: [[EXTRACT:%.*]] = extractelement <2 x float> [[SELECT]], i32 0 +; CHECK-NEXT: ret float [[EXTRACT]] +; + %cmp = icmp eq i32 %c, 0 + %select = select i1 %cmp, <2 x float> <float 1.0, float 1.0>, <2 x float> <float 2.0, float 2.0> + %extract = extractelement <2 x float> %select, i32 0 + %fabs = call float @llvm.fabs.f32(float %extract) + ret float %fabs +} + +declare float @llvm.minnum.f32(float, float) +declare float @llvm.maxnum.f32(float, float) +declare double @llvm.minnum.f64(double, double) +declare double @llvm.maxnum.f64(double, double) +declare <2 x double> @llvm.minnum.v2f64(<2 x double>, <2 x double>) +declare <2 x double> @llvm.maxnum.v2f64(<2 x double>, <2 x double>) + +; From the LangRef for minnum/maxnum: +; "If either operand is a NaN, returns the other non-NaN operand." + +define double @maxnum_nan_op0(double %x) { +; CHECK-LABEL: @maxnum_nan_op0( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.maxnum.f64(double 0x7ff8000000000000, double %x) + ret double %r +} + +define double @maxnum_nan_op1(double %x) { +; CHECK-LABEL: @maxnum_nan_op1( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.maxnum.f64(double %x, double 0x7ff800000000dead) + ret double %r +} + +define double @minnum_nan_op0(double %x) { +; CHECK-LABEL: @minnum_nan_op0( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.minnum.f64(double 0x7ff8000dead00000, double %x) + ret double %r +} + +define double @minnum_nan_op1(double %x) { +; CHECK-LABEL: @minnum_nan_op1( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.minnum.f64(double %x, double 0x7ff800dead00dead) + ret double %r +} + +define <2 x double> @maxnum_nan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maxnum_nan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> <double 0x7ff8000000000000, double undef>, <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maxnum_nan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maxnum_nan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff800000000dead, double 0x7ff8ffffffffffff>) + ret <2 x double> %r +} + +define <2 x double> @minnum_nan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minnum_nan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> <double undef, double 0x7ff8000dead00000>, <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minnum_nan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minnum_nan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff800dead00dead, double 0x7ff800dead00dead>) + ret <2 x double> %r +} + +define float @maxnum_undef_op1(float %x) { +; CHECK-LABEL: @maxnum_undef_op1( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.maxnum.f32(float %x, float undef) + ret float %val +} + +define float @maxnum_undef_op0(float %x) { +; CHECK-LABEL: @maxnum_undef_op0( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.maxnum.f32(float undef, float %x) + ret float %val +} + +define float @minnum_undef_op1(float %x) { +; CHECK-LABEL: @minnum_undef_op1( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.minnum.f32(float %x, float undef) + ret float %val +} + +define float @minnum_undef_op0(float %x) { +; CHECK-LABEL: @minnum_undef_op0( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.minnum.f32(float undef, float %x) + ret float %val +} + +define float @minnum_undef_undef(float %x) { +; CHECK-LABEL: @minnum_undef_undef( +; CHECK-NEXT: ret float undef +; + %val = call float @llvm.minnum.f32(float undef, float undef) + ret float %val +} + +define float @maxnum_undef_undef(float %x) { +; CHECK-LABEL: @maxnum_undef_undef( +; CHECK-NEXT: ret float undef +; + %val = call float @llvm.maxnum.f32(float undef, float undef) + ret float %val +} + +define float @minnum_same_args(float %x) { +; CHECK-LABEL: @minnum_same_args( +; CHECK-NEXT: ret float [[X:%.*]] +; + %y = call float @llvm.minnum.f32(float %x, float %x) + ret float %y +} + +define float @maxnum_same_args(float %x) { +; CHECK-LABEL: @maxnum_same_args( +; CHECK-NEXT: ret float [[X:%.*]] +; + %y = call float @llvm.maxnum.f32(float %x, float %x) + ret float %y +} + +define float @minnum_x_minnum_x_y(float %x, float %y) { +; CHECK-LABEL: @minnum_x_minnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minnum.f32(float %x, float %y) + %b = call float @llvm.minnum.f32(float %x, float %a) + ret float %b +} + +define float @minnum_y_minnum_x_y(float %x, float %y) { +; CHECK-LABEL: @minnum_y_minnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minnum.f32(float %x, float %y) + %b = call float @llvm.minnum.f32(float %y, float %a) + ret float %b +} + +define float @minnum_x_y_minnum_x(float %x, float %y) { +; CHECK-LABEL: @minnum_x_y_minnum_x( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minnum.f32(float %x, float %y) + %b = call float @llvm.minnum.f32(float %a, float %x) + ret float %b +} + +define float @minnum_x_y_minnum_y(float %x, float %y) { +; CHECK-LABEL: @minnum_x_y_minnum_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minnum.f32(float %x, float %y) + %b = call float @llvm.minnum.f32(float %a, float %y) + ret float %b +} + +; negative test + +define float @minnum_z_minnum_x_y(float %x, float %y, float %z) { +; CHECK-LABEL: @minnum_z_minnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.minnum.f32(float [[Z:%.*]], float [[A]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.minnum.f32(float %x, float %y) + %b = call float @llvm.minnum.f32(float %z, float %a) + ret float %b +} + +; negative test + +define float @minnum_x_y_minnum_z(float %x, float %y, float %z) { +; CHECK-LABEL: @minnum_x_y_minnum_z( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.minnum.f32(float [[A]], float [[Z:%.*]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.minnum.f32(float %x, float %y) + %b = call float @llvm.minnum.f32(float %a, float %z) + ret float %b +} + +; minnum(X, -INF) --> -INF + +define float @minnum_neginf(float %x) { +; CHECK-LABEL: @minnum_neginf( +; CHECK-NEXT: ret float 0xFFF0000000000000 +; + %val = call float @llvm.minnum.f32(float %x, float 0xFFF0000000000000) + ret float %val +} + +define <2 x double> @minnum_neginf_commute_vec(<2 x double> %x) { +; CHECK-LABEL: @minnum_neginf_commute_vec( +; CHECK-NEXT: ret <2 x double> <double 0xFFF0000000000000, double 0xFFF0000000000000> +; + %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> <double 0xFFF0000000000000, double 0xFFF0000000000000>, <2 x double> %x) + ret <2 x double> %r +} + +; negative test + +define float @minnum_inf(float %x) { +; CHECK-LABEL: @minnum_inf( +; CHECK-NEXT: [[VAL:%.*]] = call float @llvm.minnum.f32(float 0x7FF0000000000000, float [[X:%.*]]) +; CHECK-NEXT: ret float [[VAL]] +; + %val = call float @llvm.minnum.f32(float 0x7FF0000000000000, float %x) + ret float %val +} +define float @maxnum_x_maxnum_x_y(float %x, float %y) { +; CHECK-LABEL: @maxnum_x_maxnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maxnum.f32(float %x, float %y) + %b = call float @llvm.maxnum.f32(float %x, float %a) + ret float %b +} + +define float @maxnum_y_maxnum_x_y(float %x, float %y) { +; CHECK-LABEL: @maxnum_y_maxnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maxnum.f32(float %x, float %y) + %b = call float @llvm.maxnum.f32(float %y, float %a) + ret float %b +} + +define float @maxnum_x_y_maxnum_x(float %x, float %y) { +; CHECK-LABEL: @maxnum_x_y_maxnum_x( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maxnum.f32(float %x, float %y) + %b = call float @llvm.maxnum.f32(float %a, float %x) + ret float %b +} + +define float @maxnum_x_y_maxnum_y(float %x, float %y) { +; CHECK-LABEL: @maxnum_x_y_maxnum_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maxnum.f32(float %x, float %y) + %b = call float @llvm.maxnum.f32(float %a, float %y) + ret float %b +} + +; negative test + +define float @maxnum_z_maxnum_x_y(float %x, float %y, float %z) { +; CHECK-LABEL: @maxnum_z_maxnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.maxnum.f32(float [[Z:%.*]], float [[A]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.maxnum.f32(float %x, float %y) + %b = call float @llvm.maxnum.f32(float %z, float %a) + ret float %b +} + +; negative test + +define float @maxnum_x_y_maxnum_z(float %x, float %y, float %z) { +; CHECK-LABEL: @maxnum_x_y_maxnum_z( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.maxnum.f32(float [[A]], float [[Z:%.*]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.maxnum.f32(float %x, float %y) + %b = call float @llvm.maxnum.f32(float %a, float %z) + ret float %b +} + +; maxnum(X, INF) --> INF + +define <2 x double> @maxnum_inf(<2 x double> %x) { +; CHECK-LABEL: @maxnum_inf( +; CHECK-NEXT: ret <2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000> +; + %val = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double><double 0x7FF0000000000000, double 0x7FF0000000000000>) + ret <2 x double> %val +} + +define float @maxnum_inf_commute(float %x) { +; CHECK-LABEL: @maxnum_inf_commute( +; CHECK-NEXT: ret float 0x7FF0000000000000 +; + %val = call float @llvm.maxnum.f32(float 0x7FF0000000000000, float %x) + ret float %val +} + +; negative test + +define float @maxnum_neginf(float %x) { +; CHECK-LABEL: @maxnum_neginf( +; CHECK-NEXT: [[VAL:%.*]] = call float @llvm.maxnum.f32(float 0xFFF0000000000000, float [[X:%.*]]) +; CHECK-NEXT: ret float [[VAL]] +; + %val = call float @llvm.maxnum.f32(float 0xFFF0000000000000, float %x) + ret float %val +} + +declare float @llvm.minimum.f32(float, float) +declare float @llvm.maximum.f32(float, float) +declare double @llvm.minimum.f64(double, double) +declare double @llvm.maximum.f64(double, double) +declare <2 x double> @llvm.minimum.v2f64(<2 x double>, <2 x double>) +declare <2 x double> @llvm.maximum.v2f64(<2 x double>, <2 x double>) + +; From the LangRef for minimum/maximum: +; "If either operand is a NaN, returns NaN." + +define double @maximum_nan_op0(double %x) { +; CHECK-LABEL: @maximum_nan_op0( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = call double @llvm.maximum.f64(double 0x7ff8000000000000, double %x) + ret double %r +} + +define double @maximum_nan_op1(double %x) { +; CHECK-LABEL: @maximum_nan_op1( +; CHECK-NEXT: ret double 0x7FF800000000DEAD +; + %r = call double @llvm.maximum.f64(double %x, double 0x7ff800000000dead) + ret double %r +} + +define double @minimum_nan_op0(double %x) { +; CHECK-LABEL: @minimum_nan_op0( +; CHECK-NEXT: ret double 0x7FF8000DEAD00000 +; + %r = call double @llvm.minimum.f64(double 0x7ff8000dead00000, double %x) + ret double %r +} + +define double @minimum_nan_op1(double %x) { +; CHECK-LABEL: @minimum_nan_op1( +; CHECK-NEXT: ret double 0x7FF800DEAD00DEAD +; + %r = call double @llvm.minimum.f64(double %x, double 0x7ff800dead00dead) + ret double %r +} + +define <2 x double> @maximum_nan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maximum_nan_op0_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef> +; + %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> <double 0x7ff8000000000000, double undef>, <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximum_nan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maximum_nan_op1_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF800000000DEAD, double 0x7FF8FFFFFFFFFFFF> +; + %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff800000000dead, double 0x7ff8ffffffffffff>) + ret <2 x double> %r +} + +define <2 x double> @minimum_nan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minimum_nan_op0_vec( +; CHECK-NEXT: ret <2 x double> <double undef, double 0x7FF8000DEAD00000> +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> <double undef, double 0x7ff8000dead00000>, <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minimum_nan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minimum_nan_op1_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF800DEAD00DEAD, double 0x7FF800DEAD00DEAD> +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff800dead00dead, double 0x7ff800dead00dead>) + ret <2 x double> %r +} + +define float @maximum_undef_op1(float %x) { +; CHECK-LABEL: @maximum_undef_op1( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.maximum.f32(float %x, float undef) + ret float %val +} + +define float @maximum_undef_op0(float %x) { +; CHECK-LABEL: @maximum_undef_op0( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.maximum.f32(float undef, float %x) + ret float %val +} + +define float @minimum_undef_op1(float %x) { +; CHECK-LABEL: @minimum_undef_op1( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.minimum.f32(float %x, float undef) + ret float %val +} + +define float @minimum_undef_op0(float %x) { +; CHECK-LABEL: @minimum_undef_op0( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.minimum.f32(float undef, float %x) + ret float %val +} + +define float @minimum_undef_undef(float %x) { +; CHECK-LABEL: @minimum_undef_undef( +; CHECK-NEXT: ret float undef +; + %val = call float @llvm.minimum.f32(float undef, float undef) + ret float %val +} + +define float @maximum_undef_undef(float %x) { +; CHECK-LABEL: @maximum_undef_undef( +; CHECK-NEXT: ret float undef +; + %val = call float @llvm.maximum.f32(float undef, float undef) + ret float %val +} + +define float @minimum_same_args(float %x) { +; CHECK-LABEL: @minimum_same_args( +; CHECK-NEXT: ret float [[X:%.*]] +; + %y = call float @llvm.minimum.f32(float %x, float %x) + ret float %y +} + +define float @maximum_same_args(float %x) { +; CHECK-LABEL: @maximum_same_args( +; CHECK-NEXT: ret float [[X:%.*]] +; + %y = call float @llvm.maximum.f32(float %x, float %x) + ret float %y +} + +define float @minimum_x_minimum_x_y(float %x, float %y) { +; CHECK-LABEL: @minimum_x_minimum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimum.f32(float %x, float %y) + %b = call float @llvm.minimum.f32(float %x, float %a) + ret float %b +} + +define float @minimum_y_minimum_x_y(float %x, float %y) { +; CHECK-LABEL: @minimum_y_minimum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimum.f32(float %x, float %y) + %b = call float @llvm.minimum.f32(float %y, float %a) + ret float %b +} + +define float @minimum_x_y_minimum_x(float %x, float %y) { +; CHECK-LABEL: @minimum_x_y_minimum_x( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimum.f32(float %x, float %y) + %b = call float @llvm.minimum.f32(float %a, float %x) + ret float %b +} + +define float @minimum_x_y_minimum_y(float %x, float %y) { +; CHECK-LABEL: @minimum_x_y_minimum_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimum.f32(float %x, float %y) + %b = call float @llvm.minimum.f32(float %a, float %y) + ret float %b +} + +; negative test + +define float @minimum_z_minimum_x_y(float %x, float %y, float %z) { +; CHECK-LABEL: @minimum_z_minimum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.minimum.f32(float [[Z:%.*]], float [[A]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.minimum.f32(float %x, float %y) + %b = call float @llvm.minimum.f32(float %z, float %a) + ret float %b +} + +; negative test + +define float @minimum_x_y_minimum_z(float %x, float %y, float %z) { +; CHECK-LABEL: @minimum_x_y_minimum_z( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.minimum.f32(float [[A]], float [[Z:%.*]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.minimum.f32(float %x, float %y) + %b = call float @llvm.minimum.f32(float %a, float %z) + ret float %b +} + +; minimum(X, -INF) --> -INF + +define float @minimum_neginf(float %x) { +; CHECK-LABEL: @minimum_neginf( +; CHECK-NEXT: ret float 0xFFF0000000000000 +; + %val = call float @llvm.minimum.f32(float %x, float 0xFFF0000000000000) + ret float %val +} + +define <2 x double> @minimum_neginf_commute_vec(<2 x double> %x) { +; CHECK-LABEL: @minimum_neginf_commute_vec( +; CHECK-NEXT: ret <2 x double> <double 0xFFF0000000000000, double 0xFFF0000000000000> +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> <double 0xFFF0000000000000, double 0xFFF0000000000000>, <2 x double> %x) + ret <2 x double> %r +} + +; negative test + +define float @minimum_inf(float %x) { +; CHECK-LABEL: @minimum_inf( +; CHECK-NEXT: [[VAL:%.*]] = call float @llvm.minimum.f32(float 0x7FF0000000000000, float [[X:%.*]]) +; CHECK-NEXT: ret float [[VAL]] +; + %val = call float @llvm.minimum.f32(float 0x7FF0000000000000, float %x) + ret float %val +} +define float @maximum_x_maximum_x_y(float %x, float %y) { +; CHECK-LABEL: @maximum_x_maximum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximum.f32(float %x, float %y) + %b = call float @llvm.maximum.f32(float %x, float %a) + ret float %b +} + +define float @maximum_y_maximum_x_y(float %x, float %y) { +; CHECK-LABEL: @maximum_y_maximum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximum.f32(float %x, float %y) + %b = call float @llvm.maximum.f32(float %y, float %a) + ret float %b +} + +define float @maximum_x_y_maximum_x(float %x, float %y) { +; CHECK-LABEL: @maximum_x_y_maximum_x( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximum.f32(float %x, float %y) + %b = call float @llvm.maximum.f32(float %a, float %x) + ret float %b +} + +define float @maximum_x_y_maximum_y(float %x, float %y) { +; CHECK-LABEL: @maximum_x_y_maximum_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximum.f32(float %x, float %y) + %b = call float @llvm.maximum.f32(float %a, float %y) + ret float %b +} + +; negative test + +define float @maximum_z_maximum_x_y(float %x, float %y, float %z) { +; CHECK-LABEL: @maximum_z_maximum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.maximum.f32(float [[Z:%.*]], float [[A]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.maximum.f32(float %x, float %y) + %b = call float @llvm.maximum.f32(float %z, float %a) + ret float %b +} + +; negative test + +define float @maximum_x_y_maximum_z(float %x, float %y, float %z) { +; CHECK-LABEL: @maximum_x_y_maximum_z( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[Z:%.*]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.maximum.f32(float %x, float %y) + %b = call float @llvm.maximum.f32(float %a, float %z) + ret float %b +} + +; maximum(X, INF) --> INF + +define <2 x double> @maximum_inf(<2 x double> %x) { +; CHECK-LABEL: @maximum_inf( +; CHECK-NEXT: ret <2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000> +; + %val = call <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double><double 0x7FF0000000000000, double 0x7FF0000000000000>) + ret <2 x double> %val +} + +define float @maximum_inf_commute(float %x) { +; CHECK-LABEL: @maximum_inf_commute( +; CHECK-NEXT: ret float 0x7FF0000000000000 +; + %val = call float @llvm.maximum.f32(float 0x7FF0000000000000, float %x) + ret float %val +} + +; Y - (Y - X) --> X + +define float @fsub_fsub_common_op(float %x, float %y) { +; CHECK-LABEL: @fsub_fsub_common_op( +; CHECK-NEXT: ret float [[X:%.*]] +; + %s = fsub float %y, %x + %r = fsub reassoc nsz float %y, %s + ret float %r +} + +define <2 x float> @fsub_fsub_common_op_vec(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @fsub_fsub_common_op_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %s = fsub <2 x float> %y, %x + %r = fsub reassoc nsz <2 x float> %y, %s + ret <2 x float> %r +} + +; Negative test - fsub is not commutative. +; Y - (X - Y) --> (Y - X) + Y (canonicalized) + +define float @fsub_fsub_wrong_common_op(float %x, float %y) { +; CHECK-LABEL: @fsub_fsub_wrong_common_op( +; CHECK-NEXT: [[S:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[Y]], [[S]] +; CHECK-NEXT: ret float [[R]] +; + %s = fsub float %x, %y + %r = fsub reassoc nsz float %y, %s + ret float %r +} + +; Negative test - negated operand needed. +; (Y - X) - Y --> -X + +define float @fsub_fsub_common_op_wrong_commute(float %x, float %y) { +; CHECK-LABEL: @fsub_fsub_common_op_wrong_commute( +; CHECK-NEXT: [[S:%.*]] = fsub float [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[S]], [[Y]] +; CHECK-NEXT: ret float [[R]] +; + %s = fsub float %y, %x + %r = fsub reassoc nsz float %s, %y + ret float %r +} + +; Negative test - fsub is not commutative. +; (X - Y) - Y --> ? + +define float @fsub_fsub_wrong_common_op_wrong_commute(float %x, float %y) { +; CHECK-LABEL: @fsub_fsub_wrong_common_op_wrong_commute( +; CHECK-NEXT: [[S:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[S]], [[Y]] +; CHECK-NEXT: ret float [[R]] +; + %s = fsub float %x, %y + %r = fsub reassoc nsz float %s, %y + ret float %r +} + +; (Y + X) - Y --> X + +define float @fadd_fsub_common_op(float %x, float %y) { +; CHECK-LABEL: @fadd_fsub_common_op( +; CHECK-NEXT: ret float [[X:%.*]] +; + %a = fadd float %y, %x + %r = fsub reassoc nsz float %a, %y + ret float %r +} + +; (X + Y) - Y --> X + +define <2 x float> @fadd_fsub_common_op_commute_vec(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @fadd_fsub_common_op_commute_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %a = fadd <2 x float> %x, %y + %r = fsub reassoc nsz <2 x float> %a, %y + ret <2 x float> %r +} + +; Negative test - negated operand needed. +; Y - (Y + X) --> -X + +define float @fadd_fsub_common_op_wrong_commute(float %x, float %y) { +; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute( +; CHECK-NEXT: [[A:%.*]] = fadd float [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[Y]], [[A]] +; CHECK-NEXT: ret float [[R]] +; + %a = fadd float %y, %x + %r = fsub reassoc nsz float %y, %a + ret float %r +} + +; Negative test - negated operand needed. +; Y - (X + Y) --> -X + +define float @fadd_fsub_common_op_wrong_commute_commute(float %x, float %y) { +; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute_commute( +; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = fsub reassoc nsz float [[Y]], [[A]] +; CHECK-NEXT: ret float [[R]] +; + %a = fadd float %x, %y + %r = fsub reassoc nsz float %y, %a + ret float %r +} + +; Y + (X - Y) --> X + +define <2 x float> @fsub_fadd_common_op_vec(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @fsub_fadd_common_op_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %s = fsub <2 x float> %x, %y + %r = fadd reassoc nsz <2 x float> %y, %s + ret <2 x float> %r +} + +; (X - Y) + Y --> X + +define float @fsub_fadd_common_op_commute(float %x, float %y) { +; CHECK-LABEL: @fsub_fadd_common_op_commute( +; CHECK-NEXT: ret float [[X:%.*]] +; + %s = fsub float %x, %y + %r = fadd reassoc nsz float %s, %y + ret float %r +} + +; Negative test. +; Y + (Y - X) --> ? + +define float @fsub_fadd_common_op_wrong_commute(float %x, float %y) { +; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute( +; CHECK-NEXT: [[S:%.*]] = fsub float [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[Y]], [[S]] +; CHECK-NEXT: ret float [[R]] +; + %s = fsub float %y, %x + %r = fadd reassoc nsz float %y, %s + ret float %r +} + +; Negative test. +; (Y - X) + Y --> ? + +define float @fsub_fadd_common_op_wrong_commute_commute(float %x, float %y) { +; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute_commute( +; CHECK-NEXT: [[S:%.*]] = fsub float [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fadd reassoc nsz float [[S]], [[Y]] +; CHECK-NEXT: ret float [[R]] +; + %s = fsub float %y, %x + %r = fadd reassoc nsz float %s, %y + ret float %r +} diff --git a/llvm/test/Transforms/InstSimplify/floating-point-compare.ll b/llvm/test/Transforms/InstSimplify/floating-point-compare.ll new file mode 100644 index 00000000000..5ce56e029d3 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/floating-point-compare.ll @@ -0,0 +1,580 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; Infinity + +define i1 @inf0(double %arg) { +; CHECK-LABEL: @inf0( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp ogt double %arg, 0x7FF0000000000000 + ret i1 %tmp +} + +define i1 @inf1(double %arg) { +; CHECK-LABEL: @inf1( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp ule double %arg, 0x7FF0000000000000 + ret i1 %tmp +} + +; Negative infinity + +define i1 @ninf0(double %arg) { +; CHECK-LABEL: @ninf0( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp olt double %arg, 0xFFF0000000000000 + ret i1 %tmp +} + +define i1 @ninf1(double %arg) { +; CHECK-LABEL: @ninf1( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp uge double %arg, 0xFFF0000000000000 + ret i1 %tmp +} + +; NaNs + +define i1 @nan0(double %arg) { +; CHECK-LABEL: @nan0( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp ord double %arg, 0x7FF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nan1(double %arg) { +; CHECK-LABEL: @nan1( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp oeq double %arg, 0x7FF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nan2(double %arg) { +; CHECK-LABEL: @nan2( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp olt double %arg, 0x7FF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nan3(double %arg) { +; CHECK-LABEL: @nan3( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp uno double %arg, 0x7FF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nan4(double %arg) { +; CHECK-LABEL: @nan4( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp une double %arg, 0x7FF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nan5(double %arg) { +; CHECK-LABEL: @nan5( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp ult double %arg, 0x7FF00000FFFFFFFF + ret i1 %tmp +} + +; Negative NaN. + +define i1 @nnan0(double %arg) { +; CHECK-LABEL: @nnan0( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp ord double %arg, 0xFFF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nnan1(double %arg) { +; CHECK-LABEL: @nnan1( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp oeq double %arg, 0xFFF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nnan2(double %arg) { +; CHECK-LABEL: @nnan2( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp olt double %arg, 0xFFF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nnan3(double %arg) { +; CHECK-LABEL: @nnan3( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp uno double %arg, 0xFFF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nnan4(double %arg) { +; CHECK-LABEL: @nnan4( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp une double %arg, 0xFFF00000FFFFFFFF + ret i1 %tmp +} + +define i1 @nnan5(double %arg) { +; CHECK-LABEL: @nnan5( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp ult double %arg, 0xFFF00000FFFFFFFF + ret i1 %tmp +} + +; Negative zero. + +define i1 @nzero0() { +; CHECK-LABEL: @nzero0( +; CHECK-NEXT: ret i1 true +; + %tmp = fcmp oeq double 0.0, -0.0 + ret i1 %tmp +} + +define i1 @nzero1() { +; CHECK-LABEL: @nzero1( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp ogt double 0.0, -0.0 + ret i1 %tmp +} + +; No enlightenment here. + +define i1 @one_with_self(double %arg) { +; CHECK-LABEL: @one_with_self( +; CHECK-NEXT: ret i1 false +; + %tmp = fcmp one double %arg, %arg + ret i1 %tmp +} + +; These tests choose arbitrarily between float and double, +; and between uge and olt, to give reasonble coverage +; without combinatorial explosion. + +declare half @llvm.fabs.f16(half) +declare float @llvm.fabs.f32(float) +declare double @llvm.fabs.f64(double) +declare <2 x float> @llvm.fabs.v2f32(<2 x float>) +declare <3 x float> @llvm.fabs.v3f32(<3 x float>) +declare <2 x double> @llvm.fabs.v2f64(<2 x double>) +declare float @llvm.sqrt.f32(float) +declare double @llvm.powi.f64(double,i32) +declare float @llvm.exp.f32(float) +declare float @llvm.minnum.f32(float, float) +declare float @llvm.maxnum.f32(float, float) +declare float @llvm.maximum.f32(float, float) +declare double @llvm.exp2.f64(double) +declare float @llvm.fma.f32(float,float,float) + +declare void @expect_equal(i1,i1) + +define i1 @orderedLessZeroTree(float,float,float,float) { +; CHECK-LABEL: @orderedLessZeroTree( +; CHECK-NEXT: ret i1 true +; + %square = fmul float %0, %0 + %abs = call float @llvm.fabs.f32(float %1) + %sqrt = call float @llvm.sqrt.f32(float %2) + %fma = call float @llvm.fma.f32(float %3, float %3, float %sqrt) + %div = fdiv float %square, %abs + %rem = frem float %sqrt, %fma + %add = fadd float %div, %rem + %uge = fcmp uge float %add, 0.000000e+00 + ret i1 %uge +} + +define i1 @orderedLessZeroExpExt(float) { +; CHECK-LABEL: @orderedLessZeroExpExt( +; CHECK-NEXT: ret i1 true +; + %a = call float @llvm.exp.f32(float %0) + %b = fpext float %a to double + %uge = fcmp uge double %b, 0.000000e+00 + ret i1 %uge +} + +define i1 @orderedLessZeroExp2Trunc(double) { +; CHECK-LABEL: @orderedLessZeroExp2Trunc( +; CHECK-NEXT: ret i1 false +; + %a = call double @llvm.exp2.f64(double %0) + %b = fptrunc double %a to float + %olt = fcmp olt float %b, 0.000000e+00 + ret i1 %olt +} + +define i1 @orderedLessZeroPowi(double,double) { +; CHECK-LABEL: @orderedLessZeroPowi( +; CHECK-NEXT: ret i1 false +; + ; Even constant exponent + %a = call double @llvm.powi.f64(double %0, i32 2) + %square = fmul double %1, %1 + ; Odd constant exponent with provably non-negative base + %b = call double @llvm.powi.f64(double %square, i32 3) + %c = fadd double %a, %b + %olt = fcmp olt double %b, 0.000000e+00 + ret i1 %olt +} + +define i1 @UIToFP_is_nan_or_positive_or_zero(i32 %x) { +; CHECK-LABEL: @UIToFP_is_nan_or_positive_or_zero( +; CHECK-NEXT: ret i1 true +; + %a = uitofp i32 %x to float + %r = fcmp uge float %a, 0.000000e+00 + ret i1 %r +} + +define <2 x i1> @UIToFP_is_nan_or_positive_or_zero_vec(<2 x i32> %x) { +; CHECK-LABEL: @UIToFP_is_nan_or_positive_or_zero_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %a = uitofp <2 x i32> %x to <2 x float> + %r = fcmp uge <2 x float> %a, zeroinitializer + ret <2 x i1> %r +} + +define i1 @UIToFP_nnan_is_positive_or_zero(i32 %x) { +; CHECK-LABEL: @UIToFP_nnan_is_positive_or_zero( +; CHECK-NEXT: ret i1 true +; + %a = uitofp i32 %x to float + %r = fcmp nnan oge float %a, 0.000000e+00 + ret i1 %r +} + +define <2 x i1> @UIToFP_nnan_is_positive_or_zero_vec(<2 x i32> %x) { +; CHECK-LABEL: @UIToFP_nnan_is_positive_or_zero_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %a = uitofp <2 x i32> %x to <2 x float> + %r = fcmp nnan oge <2 x float> %a, zeroinitializer + ret <2 x i1> %r +} + +define i1 @UIToFP_is_not_negative(i32 %x) { +; CHECK-LABEL: @UIToFP_is_not_negative( +; CHECK-NEXT: ret i1 false +; + %a = uitofp i32 %x to float + %r = fcmp olt float %a, 0.000000e+00 + ret i1 %r +} + +define <2 x i1> @UIToFP_is_not_negative_vec(<2 x i32> %x) { +; CHECK-LABEL: @UIToFP_is_not_negative_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %a = uitofp <2 x i32> %x to <2 x float> + %r = fcmp olt <2 x float> %a, zeroinitializer + ret <2 x i1> %r +} + +define i1 @UIToFP_nnan_is_not_negative(i32 %x) { +; CHECK-LABEL: @UIToFP_nnan_is_not_negative( +; CHECK-NEXT: ret i1 false +; + %a = uitofp i32 %x to float + %r = fcmp nnan ult float %a, 0.000000e+00 + ret i1 %r +} + +define <2 x i1> @UIToFP_nnan_is_not_negative_vec(<2 x i32> %x) { +; CHECK-LABEL: @UIToFP_nnan_is_not_negative_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %a = uitofp <2 x i32> %x to <2 x float> + %r = fcmp nnan ult <2 x float> %a, zeroinitializer + ret <2 x i1> %r +} + +define i1 @fabs_is_nan_or_positive_or_zero(double %x) { +; CHECK-LABEL: @fabs_is_nan_or_positive_or_zero( +; CHECK-NEXT: ret i1 true +; + %fabs = tail call double @llvm.fabs.f64(double %x) + %cmp = fcmp uge double %fabs, 0.0 + ret i1 %cmp +} + +define <2 x i1> @fabs_is_nan_or_positive_or_zero_vec(<2 x double> %x) { +; CHECK-LABEL: @fabs_is_nan_or_positive_or_zero_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x) + %cmp = fcmp uge <2 x double> %fabs, zeroinitializer + ret <2 x i1> %cmp +} + +define i1 @fabs_nnan_is_positive_or_zero(double %x) { +; CHECK-LABEL: @fabs_nnan_is_positive_or_zero( +; CHECK-NEXT: ret i1 true +; + %fabs = tail call double @llvm.fabs.f64(double %x) + %cmp = fcmp nnan oge double %fabs, 0.0 + ret i1 %cmp +} + +define <2 x i1> @fabs_nnan_is_positive_or_zero_vec(<2 x double> %x) { +; CHECK-LABEL: @fabs_nnan_is_positive_or_zero_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x) + %cmp = fcmp nnan oge <2 x double> %fabs, zeroinitializer + ret <2 x i1> %cmp +} + +define i1 @fabs_is_not_negative(double %x) { +; CHECK-LABEL: @fabs_is_not_negative( +; CHECK-NEXT: ret i1 false +; + %fabs = tail call double @llvm.fabs.f64(double %x) + %cmp = fcmp olt double %fabs, 0.0 + ret i1 %cmp +} + +define <2 x i1> @fabs_is_not_negative_vec(<2 x double> %x) { +; CHECK-LABEL: @fabs_is_not_negative_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x) + %cmp = fcmp olt <2 x double> %fabs, zeroinitializer + ret <2 x i1> %cmp +} + +define i1 @fabs_nnan_is_not_negative(double %x) { +; CHECK-LABEL: @fabs_nnan_is_not_negative( +; CHECK-NEXT: ret i1 false +; + %fabs = tail call double @llvm.fabs.f64(double %x) + %cmp = fcmp nnan ult double %fabs, 0.0 + ret i1 %cmp +} + +define <2 x i1> @fabs_nnan_is_not_negative_vec(<2 x double> %x) { +; CHECK-LABEL: @fabs_nnan_is_not_negative_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x) + %cmp = fcmp nnan ult <2 x double> %fabs, zeroinitializer + ret <2 x i1> %cmp +} + +define <2 x i1> @fabs_is_not_negative_negzero(<2 x float> %V) { +; CHECK-LABEL: @fabs_is_not_negative_negzero( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %abs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %V) + %cmp = fcmp olt <2 x float> %abs, <float -0.0, float -0.0> + ret <2 x i1> %cmp +} + +define <2 x i1> @fabs_is_not_negative_poszero(<2 x float> %V) { +; CHECK-LABEL: @fabs_is_not_negative_poszero( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %abs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %V) + %cmp = fcmp olt <2 x float> %abs, <float 0.0, float 0.0> + ret <2 x i1> %cmp +} + +define <2 x i1> @fabs_is_not_negative_anyzero(<2 x float> %V) { +; CHECK-LABEL: @fabs_is_not_negative_anyzero( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %abs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %V) + %cmp = fcmp olt <2 x float> %abs, <float 0.0, float -0.0> + ret <2 x i1> %cmp +} + +define <3 x i1> @fabs_is_not_negative_negzero_undef(<3 x float> %V) { +; CHECK-LABEL: @fabs_is_not_negative_negzero_undef( +; CHECK-NEXT: ret <3 x i1> zeroinitializer +; + %abs = call <3 x float> @llvm.fabs.v3f32(<3 x float> %V) + %cmp = fcmp olt <3 x float> %abs, <float -0.0, float -0.0, float undef> + ret <3 x i1> %cmp +} + +define <3 x i1> @fabs_is_not_negative_poszero_undef(<3 x float> %V) { +; CHECK-LABEL: @fabs_is_not_negative_poszero_undef( +; CHECK-NEXT: ret <3 x i1> zeroinitializer +; + %abs = call <3 x float> @llvm.fabs.v3f32(<3 x float> %V) + %cmp = fcmp olt <3 x float> %abs, <float 0.0, float 0.0, float undef> + ret <3 x i1> %cmp +} + +define <3 x i1> @fabs_is_not_negative_anyzero_undef(<3 x float> %V) { +; CHECK-LABEL: @fabs_is_not_negative_anyzero_undef( +; CHECK-NEXT: ret <3 x i1> zeroinitializer +; + %abs = call <3 x float> @llvm.fabs.v3f32(<3 x float> %V) + %cmp = fcmp olt <3 x float> %abs, <float 0.0, float -0.0, float undef> + ret <3 x i1> %cmp +} + +define i1 @orderedLessZeroSelect(float, float) { +; CHECK-LABEL: @orderedLessZeroSelect( +; CHECK-NEXT: ret i1 true +; + %a = call float @llvm.exp.f32(float %0) + %b = call float @llvm.fabs.f32(float %1) + %c = fcmp olt float %0, %1 + %d = select i1 %c, float %a, float %b + %e = fadd float %d, 1.0 + %uge = fcmp uge float %e, 0.000000e+00 + ret i1 %uge +} + +define i1 @orderedLessZeroMinNum(float, float) { +; CHECK-LABEL: @orderedLessZeroMinNum( +; CHECK-NEXT: ret i1 true +; + %a = call float @llvm.exp.f32(float %0) + %b = call float @llvm.fabs.f32(float %1) + %c = call float @llvm.minnum.f32(float %a, float %b) + %uge = fcmp uge float %c, 0.000000e+00 + ret i1 %uge +} + +; PR37776: https://bugs.llvm.org/show_bug.cgi?id=37776 +; exp() may return nan, leaving %1 as the unknown result, so we can't simplify. + +define i1 @orderedLessZeroMaxNum(float, float) { +; CHECK-LABEL: @orderedLessZeroMaxNum( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.exp.f32(float [[TMP0:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.maxnum.f32(float [[A]], float [[TMP1:%.*]]) +; CHECK-NEXT: [[UGE:%.*]] = fcmp uge float [[B]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[UGE]] +; + %a = call float @llvm.exp.f32(float %0) + %b = call float @llvm.maxnum.f32(float %a, float %1) + %uge = fcmp uge float %b, 0.000000e+00 + ret i1 %uge +} + +; But using maximum, we can simplify, since the NaN would be propagated + +define i1 @orderedLessZeroMaximum(float, float) { +; CHECK-LABEL: @orderedLessZeroMaximum( +; CHECK-NEXT: ret i1 true +; + %a = call float @llvm.exp.f32(float %0) + %b = call float @llvm.maximum.f32(float %a, float %1) + %uge = fcmp uge float %b, 0.000000e+00 + ret i1 %uge +} + +define i1 @known_positive_olt_with_negative_constant(double %a) { +; CHECK-LABEL: @known_positive_olt_with_negative_constant( +; CHECK-NEXT: ret i1 false +; + %call = call double @llvm.fabs.f64(double %a) + %cmp = fcmp olt double %call, -1.0 + ret i1 %cmp +} + +define <2 x i1> @known_positive_ole_with_negative_constant_splat_vec(<2 x i32> %a) { +; CHECK-LABEL: @known_positive_ole_with_negative_constant_splat_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %call = uitofp <2 x i32> %a to <2 x double> + %cmp = fcmp ole <2 x double> %call, <double -2.0, double -2.0> + ret <2 x i1> %cmp +} + +define i1 @known_positive_ugt_with_negative_constant(i32 %a) { +; CHECK-LABEL: @known_positive_ugt_with_negative_constant( +; CHECK-NEXT: ret i1 true +; + %call = uitofp i32 %a to float + %cmp = fcmp ugt float %call, -3.0 + ret i1 %cmp +} + +define <2 x i1> @known_positive_uge_with_negative_constant_splat_vec(<2 x float> %a) { +; CHECK-LABEL: @known_positive_uge_with_negative_constant_splat_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a) + %cmp = fcmp uge <2 x float> %call, <float -4.0, float -4.0> + ret <2 x i1> %cmp +} + +define i1 @known_positive_oeq_with_negative_constant(half %a) { +; CHECK-LABEL: @known_positive_oeq_with_negative_constant( +; CHECK-NEXT: ret i1 false +; + %call = call half @llvm.fabs.f16(half %a) + %cmp = fcmp oeq half %call, -5.0 + ret i1 %cmp +} + +define <2 x i1> @known_positive_une_with_negative_constant_splat_vec(<2 x i32> %a) { +; CHECK-LABEL: @known_positive_une_with_negative_constant_splat_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %call = uitofp <2 x i32> %a to <2 x half> + %cmp = fcmp une <2 x half> %call, <half -6.0, half -6.0> + ret <2 x i1> %cmp +} + +define i1 @nonans1(double %in1, double %in2) { +; CHECK-LABEL: @nonans1( +; CHECK-NEXT: ret i1 false +; + %cmp = fcmp nnan uno double %in1, %in2 + ret i1 %cmp +} + +define i1 @nonans2(double %in1, double %in2) { +; CHECK-LABEL: @nonans2( +; CHECK-NEXT: ret i1 true +; + %cmp = fcmp nnan ord double %in1, %in2 + ret i1 %cmp +} + +define <2 x i1> @orderedCompareWithNaNVector(<2 x double> %A) { +; CHECK-LABEL: @orderedCompareWithNaNVector( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %cmp = fcmp olt <2 x double> %A, <double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF> + ret <2 x i1> %cmp +} + +define <2 x i1> @orderedCompareWithNaNVector_undef_elt(<2 x double> %A) { +; CHECK-LABEL: @orderedCompareWithNaNVector_undef_elt( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %cmp = fcmp olt <2 x double> %A, <double 0xFFFFFFFFFFFFFFFF, double undef> + ret <2 x i1> %cmp +} + +define <2 x i1> @unorderedCompareWithNaNVector_undef_elt(<2 x double> %A) { +; CHECK-LABEL: @unorderedCompareWithNaNVector_undef_elt( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %cmp = fcmp ult <2 x double> %A, <double undef, double 0xFFFFFFFFFFFFFFFF> + ret <2 x i1> %cmp +} diff --git a/llvm/test/Transforms/InstSimplify/fold-builtin-fma.ll b/llvm/test/Transforms/InstSimplify/fold-builtin-fma.ll new file mode 100644 index 00000000000..6331b8c2dd4 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fold-builtin-fma.ll @@ -0,0 +1,119 @@ +; RUN: opt -instsimplify -S < %s | FileCheck %s + +; Fixes PR20832 +; Make sure that we correctly fold a fused multiply-add where operands +; are all finite constants and addend is zero. + +declare double @llvm.fma.f64(double, double, double) + + +define double @PR20832() { + %1 = call double @llvm.fma.f64(double 7.0, double 8.0, double 0.0) + ret double %1 +} +; CHECK-LABEL: @PR20832( +; CHECK: ret double 5.600000e+01 + +; Test builtin fma with all finite non-zero constants. +define double @test_all_finite() { + %1 = call double @llvm.fma.f64(double 7.0, double 8.0, double 5.0) + ret double %1 +} +; CHECK-LABEL: @test_all_finite( +; CHECK: ret double 6.100000e+01 + +; Test builtin fma with a +/-NaN addend. +define double @test_NaN_addend() { + %1 = call double @llvm.fma.f64(double 7.0, double 8.0, double 0x7FF8000000000000) + ret double %1 +} +; CHECK-LABEL: @test_NaN_addend( +; CHECK: ret double 0x7FF8000000000000 + +define double @test_NaN_addend_2() { + %1 = call double @llvm.fma.f64(double 7.0, double 8.0, double 0xFFF8000000000000) + ret double %1 +} +; CHECK-LABEL: @test_NaN_addend_2( +; CHECK: ret double 0xFFF8000000000000 + +; Test builtin fma with a +/-Inf addend. +define double @test_Inf_addend() { + %1 = call double @llvm.fma.f64(double 7.0, double 8.0, double 0x7FF0000000000000) + ret double %1 +} +; CHECK-LABEL: @test_Inf_addend( +; CHECK: ret double 0x7FF0000000000000 + +define double @test_Inf_addend_2() { + %1 = call double @llvm.fma.f64(double 7.0, double 8.0, double 0xFFF0000000000000) + ret double %1 +} +; CHECK-LABEL: @test_Inf_addend_2( +; CHECK: ret double 0xFFF0000000000000 + +; Test builtin fma with one of the operands to the multiply being +/-NaN. +define double @test_NaN_1() { + %1 = call double @llvm.fma.f64(double 0x7FF8000000000000, double 8.0, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_NaN_1( +; CHECK: ret double 0x7FF8000000000000 + + +define double @test_NaN_2() { + %1 = call double @llvm.fma.f64(double 7.0, double 0x7FF8000000000000, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_NaN_2( +; CHECK: ret double 0x7FF8000000000000 + + +define double @test_NaN_3() { + %1 = call double @llvm.fma.f64(double 0xFFF8000000000000, double 8.0, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_NaN_3( +; CHECK: ret double 0x7FF8000000000000 + + +define double @test_NaN_4() { + %1 = call double @llvm.fma.f64(double 7.0, double 0xFFF8000000000000, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_NaN_4( +; CHECK: ret double 0x7FF8000000000000 + + +; Test builtin fma with one of the operands to the multiply being +/-Inf. +define double @test_Inf_1() { + %1 = call double @llvm.fma.f64(double 0x7FF0000000000000, double 8.0, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_Inf_1( +; CHECK: ret double 0x7FF0000000000000 + + +define double @test_Inf_2() { + %1 = call double @llvm.fma.f64(double 7.0, double 0x7FF0000000000000, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_Inf_2( +; CHECK: ret double 0x7FF0000000000000 + + +define double @test_Inf_3() { + %1 = call double @llvm.fma.f64(double 0xFFF0000000000000, double 8.0, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_Inf_3( +; CHECK: ret double 0xFFF0000000000000 + + +define double @test_Inf_4() { + %1 = call double @llvm.fma.f64(double 7.0, double 0xFFF0000000000000, double 0.0) + ret double %1 +} +; CHECK-LABEL: @test_Inf_4( +; CHECK: ret double 0xFFF0000000000000 + diff --git a/llvm/test/Transforms/InstSimplify/fold-intrinsics.ll b/llvm/test/Transforms/InstSimplify/fold-intrinsics.ll new file mode 100644 index 00000000000..e484704e8a7 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fold-intrinsics.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +declare double @llvm.powi.f64(double, i32) nounwind readonly +declare i32 @llvm.bswap.i32(i32) + +; A +define i32 @test_bswap(i32 %a) nounwind { +; CHECK-LABEL: @test_bswap( +; CHECK-NEXT: ret i32 %a +; + %tmp2 = tail call i32 @llvm.bswap.i32( i32 %a ) + %tmp4 = tail call i32 @llvm.bswap.i32( i32 %tmp2 ) + ret i32 %tmp4 +} + +define void @powi(double %V, double *%P) { + %B = tail call double @llvm.powi.f64(double %V, i32 0) nounwind + store volatile double %B, double* %P + + %C = tail call double @llvm.powi.f64(double %V, i32 1) nounwind + store volatile double %C, double* %P + + ret void +; CHECK-LABEL: @powi( +; CHECK: store volatile double 1.0 +; CHECK: store volatile double %V +} diff --git a/llvm/test/Transforms/InstSimplify/fp-nan.ll b/llvm/test/Transforms/InstSimplify/fp-nan.ll new file mode 100644 index 00000000000..4096ca4ddb0 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fp-nan.ll @@ -0,0 +1,201 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; Default NaN constant + +define double @fadd_nan_op0(double %x) { +; CHECK-LABEL: @fadd_nan_op0( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fadd double 0x7FF8000000000000, %x + ret double %r +} + +; Sign bit is set + +define double @fadd_nan_op1(double %x) { +; CHECK-LABEL: @fadd_nan_op1( +; CHECK-NEXT: ret double 0xFFF8000000000000 +; + %r = fadd double %x, 0xFFF8000000000000 + ret double %r +} + +; Non-zero payload + +define float @fsub_nan_op0(float %x) { +; CHECK-LABEL: @fsub_nan_op0( +; CHECK-NEXT: ret float 0x7FFFFF0000000000 +; + %r = fsub float 0x7FFFFF0000000000, %x + ret float %r +} + +; Signaling + +define float @fsub_nan_op1(float %x) { +; CHECK-LABEL: @fsub_nan_op1( +; CHECK-NEXT: ret float 0x7FF1000000000000 +; + %r = fsub float %x, 0x7FF1000000000000 + ret float %r +} + +; Signaling and signed + +define double @fmul_nan_op0(double %x) { +; CHECK-LABEL: @fmul_nan_op0( +; CHECK-NEXT: ret double 0xFFF0000000000001 +; + %r = fmul double 0xFFF0000000000001, %x + ret double %r +} + +; Vector type + +define <2 x float> @fmul_nan_op1(<2 x float> %x) { +; CHECK-LABEL: @fmul_nan_op1( +; CHECK-NEXT: ret <2 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000> +; + %r = fmul <2 x float> %x, <float 0x7FF8000000000000, float 0x7FF8000000000000> + ret <2 x float> %r +} + +; Vector signed and non-zero payload + +define <2 x double> @fdiv_nan_op0(<2 x double> %x) { +; CHECK-LABEL: @fdiv_nan_op0( +; CHECK-NEXT: ret <2 x double> <double 0xFFF800000000000F, double 0xFFF800000000000F> +; + %r = fdiv <2 x double> <double 0xFFF800000000000F, double 0xFFF800000000000F>, %x + ret <2 x double> %r +} + +; Vector with different NaN constant elements + +define <2 x half> @fdiv_nan_op1(<2 x half> %x) { +; CHECK-LABEL: @fdiv_nan_op1( +; CHECK-NEXT: ret <2 x half> <half 0xH7FFF, half 0xHFF00> +; + %r = fdiv <2 x half> %x, <half 0xH7FFF, half 0xHFF00> + ret <2 x half> %r +} + +; Vector with undef element + +define <2 x double> @frem_nan_op0(<2 x double> %x) { +; CHECK-LABEL: @frem_nan_op0( +; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double 0x7FF8000000000000> +; + %r = frem <2 x double> <double 0xFFFF000000000000, double undef>, %x + ret <2 x double> %r +} + +define float @frem_nan_op1(float %x) { +; CHECK-LABEL: @frem_nan_op1( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem float %x, 0x7FF8000000000000 + ret float %r +} + +; Special-case: fneg must only change the sign bit (this is handled by constant folding). + +define double @fneg_nan_1(double %x) { +; CHECK-LABEL: @fneg_nan_1( +; CHECK-NEXT: ret double 0xFFFABCDEF0123456 +; + %r = fsub double -0.0, 0x7FFABCDEF0123456 + ret double %r +} + +define <2 x double> @fneg_nan_2(<2 x double> %x) { +; CHECK-LABEL: @fneg_nan_2( +; CHECK-NEXT: ret <2 x double> <double 0x7FF1234567890ABC, double 0xFFF0000000000001> +; + %r = fsub <2 x double> <double -0.0, double -0.0>, <double 0xFFF1234567890ABC, double 0x7FF0000000000001> + ret <2 x double> %r +} + +; Repeat all tests with fast-math-flags. Alternate 'nnan' and 'fast' for more coverage. + +define float @fadd_nan_op0_nnan(float %x) { +; CHECK-LABEL: @fadd_nan_op0_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd nnan float 0x7FF8000000000000, %x + ret float %r +} + +define float @fadd_nan_op1_fast(float %x) { +; CHECK-LABEL: @fadd_nan_op1_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd fast float %x, 0x7FF8000000000000 + ret float %r +} + +define float @fsub_nan_op0_fast(float %x) { +; CHECK-LABEL: @fsub_nan_op0_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub fast float 0x7FF8000000000000, %x + ret float %r +} + +define float @fsub_nan_op1_nnan(float %x) { +; CHECK-LABEL: @fsub_nan_op1_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub nnan float %x, 0x7FF8000000000000 + ret float %r +} + +define float @fmul_nan_op0_nnan(float %x) { +; CHECK-LABEL: @fmul_nan_op0_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul nnan float 0x7FF8000000000000, %x + ret float %r +} + +define float @fmul_nan_op1_fast(float %x) { +; CHECK-LABEL: @fmul_nan_op1_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul fast float %x, 0x7FF8000000000000 + ret float %r +} + +define float @fdiv_nan_op0_fast(float %x) { +; CHECK-LABEL: @fdiv_nan_op0_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv fast float 0x7FF8000000000000, %x + ret float %r +} + +define float @fdiv_nan_op1_nnan(float %x) { +; CHECK-LABEL: @fdiv_nan_op1_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv nnan float %x, 0x7FF8000000000000 + ret float %r +} + +define float @frem_nan_op0_nnan(float %x) { +; CHECK-LABEL: @frem_nan_op0_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem nnan float 0x7FF8000000000000, %x + ret float %r +} + +define float @frem_nan_op1_fast(float %x) { +; CHECK-LABEL: @frem_nan_op1_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem fast float %x, 0x7FF8000000000000 + ret float %r +} + diff --git a/llvm/test/Transforms/InstSimplify/fp-undef.ll b/llvm/test/Transforms/InstSimplify/fp-undef.ll new file mode 100644 index 00000000000..f4a71e99a87 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/fp-undef.ll @@ -0,0 +1,533 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define float @fadd_undef_op0(float %x) { +; CHECK-LABEL: @fadd_undef_op0( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd float undef, %x + ret float %r +} + +define float @fadd_undef_op1(float %x) { +; CHECK-LABEL: @fadd_undef_op1( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd float %x, undef + ret float %r +} + +define float @fsub_undef_op0(float %x) { +; CHECK-LABEL: @fsub_undef_op0( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub float undef, %x + ret float %r +} + +define float @fsub_undef_op1(float %x) { +; CHECK-LABEL: @fsub_undef_op1( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub float %x, undef + ret float %r +} + +define float @fmul_undef_op0(float %x) { +; CHECK-LABEL: @fmul_undef_op0( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul float undef, %x + ret float %r +} + +define float @fmul_undef_op1(float %x) { +; CHECK-LABEL: @fmul_undef_op1( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul float %x, undef + ret float %r +} + +define float @fdiv_undef_op0(float %x) { +; CHECK-LABEL: @fdiv_undef_op0( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv float undef, %x + ret float %r +} + +define float @fdiv_undef_op1(float %x) { +; CHECK-LABEL: @fdiv_undef_op1( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv float %x, undef + ret float %r +} + +define float @frem_undef_op0(float %x) { +; CHECK-LABEL: @frem_undef_op0( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem float undef, %x + ret float %r +} + +define float @frem_undef_op1(float %x) { +; CHECK-LABEL: @frem_undef_op1( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem float %x, undef + ret float %r +} + +; Repeat all tests with fast-math-flags. Alternate 'nnan' and 'fast' for more coverage. + +define float @fadd_undef_op0_nnan(float %x) { +; CHECK-LABEL: @fadd_undef_op0_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd nnan float undef, %x + ret float %r +} + +define float @fadd_undef_op1_fast(float %x) { +; CHECK-LABEL: @fadd_undef_op1_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd fast float %x, undef + ret float %r +} + +define float @fsub_undef_op0_fast(float %x) { +; CHECK-LABEL: @fsub_undef_op0_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub fast float undef, %x + ret float %r +} + +define float @fsub_undef_op1_nnan(float %x) { +; CHECK-LABEL: @fsub_undef_op1_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub nnan float %x, undef + ret float %r +} + +define float @fmul_undef_op0_nnan(float %x) { +; CHECK-LABEL: @fmul_undef_op0_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul nnan float undef, %x + ret float %r +} + +define float @fmul_undef_op1_fast(float %x) { +; CHECK-LABEL: @fmul_undef_op1_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul fast float %x, undef + ret float %r +} + +define float @fdiv_undef_op0_fast(float %x) { +; CHECK-LABEL: @fdiv_undef_op0_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv fast float undef, %x + ret float %r +} + +define float @fdiv_undef_op1_nnan(float %x) { +; CHECK-LABEL: @fdiv_undef_op1_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv nnan float %x, undef + ret float %r +} + +define float @frem_undef_op0_nnan(float %x) { +; CHECK-LABEL: @frem_undef_op0_nnan( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem nnan float undef, %x + ret float %r +} + +define float @frem_undef_op1_fast(float %x) { +; CHECK-LABEL: @frem_undef_op1_fast( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem fast float %x, undef + ret float %r +} + +; Constant folding - undef undef. + +define double @fadd_undef_undef(double %x) { +; CHECK-LABEL: @fadd_undef_undef( +; CHECK-NEXT: ret double undef +; + %r = fadd double undef, undef + ret double %r +} + +define double @fsub_undef_undef(double %x) { +; CHECK-LABEL: @fsub_undef_undef( +; CHECK-NEXT: ret double undef +; + %r = fsub double undef, undef + ret double %r +} + +define double @fmul_undef_undef(double %x) { +; CHECK-LABEL: @fmul_undef_undef( +; CHECK-NEXT: ret double undef +; + %r = fmul double undef, undef + ret double %r +} + +define double @fdiv_undef_undef(double %x) { +; CHECK-LABEL: @fdiv_undef_undef( +; CHECK-NEXT: ret double undef +; + %r = fdiv double undef, undef + ret double %r +} + +define double @frem_undef_undef(double %x) { +; CHECK-LABEL: @frem_undef_undef( +; CHECK-NEXT: ret double undef +; + %r = frem double undef, undef + ret double %r +} + +; Constant folding. + +define float @fadd_undef_op0_nnan_constant(float %x) { +; CHECK-LABEL: @fadd_undef_op0_nnan_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd nnan float undef, 1.0 + ret float %r +} + +define float @fadd_undef_op1_constant(float %x) { +; CHECK-LABEL: @fadd_undef_op1_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fadd float 2.0, undef + ret float %r +} + +define float @fsub_undef_op0_fast_constant(float %x) { +; CHECK-LABEL: @fsub_undef_op0_fast_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub fast float undef, 3.0 + ret float %r +} + +define float @fsub_undef_op1_constant(float %x) { +; CHECK-LABEL: @fsub_undef_op1_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fsub float 4.0, undef + ret float %r +} + +define float @fmul_undef_op0_nnan_constant(float %x) { +; CHECK-LABEL: @fmul_undef_op0_nnan_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul nnan float undef, 5.0 + ret float %r +} + +define float @fmul_undef_op1_constant(float %x) { +; CHECK-LABEL: @fmul_undef_op1_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fmul float 6.0, undef + ret float %r +} + +define float @fdiv_undef_op0_fast_constant(float %x) { +; CHECK-LABEL: @fdiv_undef_op0_fast_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv fast float undef, 7.0 + ret float %r +} + +define float @fdiv_undef_op1_constant(float %x) { +; CHECK-LABEL: @fdiv_undef_op1_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = fdiv float 8.0, undef + ret float %r +} + +define float @frem_undef_op0_nnan_constant(float %x) { +; CHECK-LABEL: @frem_undef_op0_nnan_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem nnan float undef, 9.0 + ret float %r +} + +define float @frem_undef_op1_constant(float %x) { +; CHECK-LABEL: @frem_undef_op1_constant( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = frem float 10.0, undef + ret float %r +} + +; Constant folding - special constants: NaN. + +define double @fadd_undef_op0_constant_nan(double %x) { +; CHECK-LABEL: @fadd_undef_op0_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fadd double undef, 0x7FF8000000000000 + ret double %r +} + +define double @fadd_undef_op1_fast_constant_nan(double %x) { +; CHECK-LABEL: @fadd_undef_op1_fast_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fadd fast double 0xFFF0000000000001, undef + ret double %r +} + +define double @fsub_undef_op0_constant_nan(double %x) { +; CHECK-LABEL: @fsub_undef_op0_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fsub double undef, 0xFFF8000000000010 + ret double %r +} + +define double @fsub_undef_op1_nnan_constant_nan(double %x) { +; CHECK-LABEL: @fsub_undef_op1_nnan_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fsub nnan double 0x7FF0000000000011, undef + ret double %r +} + +define double @fmul_undef_op0_constant_nan(double %x) { +; CHECK-LABEL: @fmul_undef_op0_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fmul double undef, 0x7FF8000000000100 + ret double %r +} + +define double @fmul_undef_op1_fast_constant_nan(double %x) { +; CHECK-LABEL: @fmul_undef_op1_fast_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fmul fast double 0xFFF0000000000101, undef + ret double %r +} + +define double @fdiv_undef_op0_constant_nan(double %x) { +; CHECK-LABEL: @fdiv_undef_op0_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fdiv double undef, 0xFFF8000000000110 + ret double %r +} + +define double @fdiv_undef_op1_nnan_constant_nan(double %x) { +; CHECK-LABEL: @fdiv_undef_op1_nnan_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fdiv nnan double 0x7FF0000000000111, undef + ret double %r +} + +define double @frem_undef_op0_constant_nan(double %x) { +; CHECK-LABEL: @frem_undef_op0_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = frem double undef, 0x7FF8000000001000 + ret double %r +} + +define double @frem_undef_op1_fast_constant_nan(double %x) { +; CHECK-LABEL: @frem_undef_op1_fast_constant_nan( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = frem fast double 0xFFF0000000001001, undef + ret double %r +} + +; Constant folding - special constants: Inf. + +define double @fadd_undef_op0_constant_inf(double %x) { +; CHECK-LABEL: @fadd_undef_op0_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fadd double undef, 0x7FF0000000000000 + ret double %r +} + +define double @fadd_undef_op1_fast_constant_inf(double %x) { +; CHECK-LABEL: @fadd_undef_op1_fast_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fadd fast double 0xFFF0000000000000, undef + ret double %r +} + +define double @fsub_undef_op0_constant_inf(double %x) { +; CHECK-LABEL: @fsub_undef_op0_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fsub double undef, 0xFFF0000000000000 + ret double %r +} + +define double @fsub_undef_op1_ninf_constant_inf(double %x) { +; CHECK-LABEL: @fsub_undef_op1_ninf_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fsub ninf double 0x7FF0000000000000, undef + ret double %r +} + +define double @fmul_undef_op0_constant_inf(double %x) { +; CHECK-LABEL: @fmul_undef_op0_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fmul double undef, 0x7FF0000000000000 + ret double %r +} + +define double @fmul_undef_op1_fast_constant_inf(double %x) { +; CHECK-LABEL: @fmul_undef_op1_fast_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fmul fast double 0xFFF0000000000000, undef + ret double %r +} + +define double @fdiv_undef_op0_constant_inf(double %x) { +; CHECK-LABEL: @fdiv_undef_op0_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fdiv double undef, 0xFFF0000000000000 + ret double %r +} + +define double @fdiv_undef_op1_ninf_constant_inf(double %x) { +; CHECK-LABEL: @fdiv_undef_op1_ninf_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = fdiv ninf double 0x7FF0000000000000, undef + ret double %r +} + +define double @frem_undef_op0_constant_inf(double %x) { +; CHECK-LABEL: @frem_undef_op0_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = frem double undef, 0x7FF0000000000000 + ret double %r +} + +define double @frem_undef_op1_fast_constant_inf(double %x) { +; CHECK-LABEL: @frem_undef_op1_fast_constant_inf( +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %r = frem fast double 0xFFF0000000000000, undef + ret double %r +} + +define <2 x double> @fadd_undef_op1_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fadd_undef_op1_constant_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef> +; + %r = fadd <2 x double> <double 42.0, double undef>, undef + ret <2 x double> %r +} + +define <2 x double> @fadd_undef_op0_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fadd_undef_op0_constant_vec( +; CHECK-NEXT: ret <2 x double> <double undef, double 0x7FF8000000000000> +; + %r = fadd <2 x double> undef, <double undef, double 42.0> + ret <2 x double> %r +} + +define <2 x double> @fsub_undef_op1_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fsub_undef_op1_constant_vec( +; CHECK-NEXT: ret <2 x double> <double undef, double 0x7FF8000000000000> +; + %r = fsub <2 x double> <double undef, double 42.0>, undef + ret <2 x double> %r +} + +define <2 x double> @fsub_undef_op0_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fsub_undef_op0_constant_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef> +; + %r = fsub <2 x double> undef, <double 42.0, double undef> + ret <2 x double> %r +} + +define <2 x double> @fmul_undef_op1_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fmul_undef_op1_constant_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef> +; + %r = fmul <2 x double> <double 42.0, double undef>, undef + ret <2 x double> %r +} + +define <2 x double> @fmul_undef_op0_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fmul_undef_op0_constant_vec( +; CHECK-NEXT: ret <2 x double> <double undef, double 0x7FF8000000000000> +; + %r = fmul <2 x double> undef, <double undef, double 42.0> + ret <2 x double> %r +} + +define <2 x double> @fdiv_undef_op1_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fdiv_undef_op1_constant_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef> +; + %r = fdiv <2 x double> <double 42.0, double undef>, undef + ret <2 x double> %r +} + +define <2 x double> @fdiv_undef_op0_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @fdiv_undef_op0_constant_vec( +; CHECK-NEXT: ret <2 x double> <double undef, double 0x7FF8000000000000> +; + %r = fdiv <2 x double> undef, <double undef, double 42.0> + ret <2 x double> %r +} + +define <2 x double> @frem_undef_op1_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @frem_undef_op1_constant_vec( +; CHECK-NEXT: ret <2 x double> <double undef, double 0x7FF8000000000000> +; + %r = frem <2 x double> <double undef, double 42.0>, undef + ret <2 x double> %r +} + +define <2 x double> @frem_undef_op0_constant_vec(<2 x double> %x) { +; CHECK-LABEL: @frem_undef_op0_constant_vec( +; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef> +; + %r = frem <2 x double> undef, <double 42.0, double undef> + ret <2 x double> %r +} + diff --git a/llvm/test/Transforms/InstSimplify/gep.ll b/llvm/test/Transforms/InstSimplify/gep.ll new file mode 100644 index 00000000000..1fb88277783 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/gep.ll @@ -0,0 +1,105 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instsimplify < %s | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +%struct.A = type { [7 x i8] } + +define %struct.A* @test1(%struct.A* %b, %struct.A* %e) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: ret %struct.A* [[E:%.*]] +; + %e_ptr = ptrtoint %struct.A* %e to i64 + %b_ptr = ptrtoint %struct.A* %b to i64 + %sub = sub i64 %e_ptr, %b_ptr + %sdiv = sdiv exact i64 %sub, 7 + %gep = getelementptr inbounds %struct.A, %struct.A* %b, i64 %sdiv + ret %struct.A* %gep +} + +define i8* @test2(i8* %b, i8* %e) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: ret i8* [[E:%.*]] +; + %e_ptr = ptrtoint i8* %e to i64 + %b_ptr = ptrtoint i8* %b to i64 + %sub = sub i64 %e_ptr, %b_ptr + %gep = getelementptr inbounds i8, i8* %b, i64 %sub + ret i8* %gep +} + +define i64* @test3(i64* %b, i64* %e) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: ret i64* [[E:%.*]] +; + %e_ptr = ptrtoint i64* %e to i64 + %b_ptr = ptrtoint i64* %b to i64 + %sub = sub i64 %e_ptr, %b_ptr + %ashr = ashr exact i64 %sub, 3 + %gep = getelementptr inbounds i64, i64* %b, i64 %ashr + ret i64* %gep +} + +define %struct.A* @test4(%struct.A* %b) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: ret %struct.A* null +; + %b_ptr = ptrtoint %struct.A* %b to i64 + %sub = sub i64 0, %b_ptr + %sdiv = sdiv exact i64 %sub, 7 + %gep = getelementptr inbounds %struct.A, %struct.A* %b, i64 %sdiv + ret %struct.A* %gep +} + +define i8* @test5(i8* %b) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: ret i8* null +; + %b_ptr = ptrtoint i8* %b to i64 + %sub = sub i64 0, %b_ptr + %gep = getelementptr inbounds i8, i8* %b, i64 %sub + ret i8* %gep +} + +define i64* @test6(i64* %b) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: ret i64* null +; + %b_ptr = ptrtoint i64* %b to i64 + %sub = sub i64 0, %b_ptr + %ashr = ashr exact i64 %sub, 3 + %gep = getelementptr inbounds i64, i64* %b, i64 %ashr + ret i64* %gep +} + +define i8* @test7(i8* %b, i8** %e) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: [[E_PTR:%.*]] = ptrtoint i8** [[E:%.*]] to i64 +; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i8* [[B:%.*]] to i64 +; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[E_PTR]], [[B_PTR]] +; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[B]], i64 [[SUB]] +; CHECK-NEXT: ret i8* [[GEP]] +; + %e_ptr = ptrtoint i8** %e to i64 + %b_ptr = ptrtoint i8* %b to i64 + %sub = sub i64 %e_ptr, %b_ptr + %gep = getelementptr inbounds i8, i8* %b, i64 %sub + ret i8* %gep +} + +define <8 x i64*> @undef_vec1() { +; CHECK-LABEL: @undef_vec1( +; CHECK-NEXT: ret <8 x i64*> undef +; + %el = getelementptr inbounds i64, i64* undef, <8 x i64> undef + ret <8 x i64*> %el +} + +define <8 x i64*> @undef_vec2() { +; CHECK-LABEL: @undef_vec2( +; CHECK-NEXT: ret <8 x i64*> undef +; + %el = getelementptr i64, <8 x i64*> undef, <8 x i64> undef + ret <8 x i64*> %el +} + diff --git a/llvm/test/Transforms/InstSimplify/icmp-abs-nabs.ll b/llvm/test/Transforms/InstSimplify/icmp-abs-nabs.ll new file mode 100644 index 00000000000..be2e7b4d4a6 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/icmp-abs-nabs.ll @@ -0,0 +1,403 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; This is canonical form for this IR. + +define i1 @abs_nsw_is_positive(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, -1 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of abs(). + +define i1 @abs_nsw_is_positive_sge(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_sge( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 1 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sge i32 %abs, 0 + ret i1 %r +} + +; This is a range-based analysis. Any negative constant works. + +define i1 @abs_nsw_is_positive_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_reduced_range( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, -42 + ret i1 %r +} + +; Negative test - we need 'nsw' in the abs(). + +define i1 @abs_is_positive_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_is_positive_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[ABS]], 42 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, 42 + ret i1 %r +} + +; Negative test - range intersection is not subset. + +define i1 @abs_nsw_is_positive_wrong_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[ABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, 0 + ret i1 %r +} + +; This is canonical form for this IR. + +define i1 @abs_nsw_is_not_negative(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp slt i32 %abs, 0 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of abs(). + +define i1 @abs_nsw_is_not_negative_sle(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_sle( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 1 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sle i32 %abs, -1 + ret i1 %r +} + +; This is a range-based analysis. Any negative constant works. + +define i1 @abs_nsw_is_not_negative_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_reduced_range( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp slt i32 %abs, -24 + ret i1 %r +} + +; Negative test - we need 'nsw' in the abs(). + +define i1 @abs_is_not_negative_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_is_not_negative_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[ABS]], 42 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp slt i32 %abs, 42 + ret i1 %r +} + +; Negative test - range intersection is not empty. + +define i1 @abs_nsw_is_not_negative_wrong_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sle i32 [[ABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sle i32 %abs, 0 + ret i1 %r +} + +; Even if we don't have nsw, the range is still limited in the unsigned domain. +define i1 @abs_positive_or_signed_min(i32 %x) { +; CHECK-LABEL: @abs_positive_or_signed_min( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp ult i32 %abs, 2147483649 + ret i1 %r +} + +define i1 @abs_positive_or_signed_min_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_positive_or_signed_min_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[ABS]], -2147483648 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp ult i32 %abs, 2147483648 + ret i1 %r +} + +; This is canonical form for this IR. For nabs(), we don't require 'nsw' + +define i1 @nabs_is_negative_or_0(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp slt i32 %nabs, 1 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of nabs(). + +define i1 @nabs_is_negative_or_0_sle(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_sle( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sle i32 %nabs, 0 + ret i1 %r +} + +; This is a range-based analysis. Any positive constant works. + +define i1 @nabs_is_negative_or_0_reduced_range(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_reduced_range( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp slt i32 %nabs, 421 + ret i1 %r +} + +; Negative test - range intersection is not subset. + +define i1 @nabs_is_negative_or_0_wrong_range(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[NABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp slt i32 %nabs, 0 + ret i1 %r +} + +; This is canonical form for this IR. For nabs(), we don't require 'nsw' + +define i1 @nabs_is_not_over_0(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sgt i32 %nabs, 0 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of nabs(). + +define i1 @nabs_is_not_over_0_sle(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0_sle( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sge i32 %nabs, 1 + ret i1 %r +} + +; This is a range-based analysis. Any positive constant works. + +define i1 @nabs_is_not_over_0_reduced_range(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0_reduced_range( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sgt i32 %nabs, 4223 + ret i1 %r +} + +; Negative test - range intersection is not subset. + +define i1 @nabs_is_not_over_0_wrong_range(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[NABS]], -1 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sgt i32 %nabs, -1 + ret i1 %r +} + +; More miscellaneous tests for predicates/types. + +; Equality predicates are ok. + +define i1 @abs_nsw_is_positive_eq(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_eq( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 1 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp eq i32 %abs, -8 + ret i1 %r +} + +; An unsigned compare may work. + +define i1 @abs_nsw_is_positive_ult(i8 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_ult( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i8 %x, 0 + %negx = sub nsw i8 0, %x + %abs = select i1 %cmp, i8 %negx, i8 %x + %r = icmp ult i8 %abs, 139 + ret i1 %r +} + +; An unsigned compare may work. + +define i1 @abs_nsw_is_not_negative_ugt(i8 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_ugt( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i8 %x, 0 + %negx = sub nsw i8 0, %x + %abs = select i1 %cmp, i8 %negx, i8 %x + %r = icmp ugt i8 %abs, 127 + ret i1 %r +} + +; Vector types are ok. + +define <2 x i1> @abs_nsw_is_not_negative_vec_splat(<2 x i32> %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_vec_splat( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %cmp = icmp slt <2 x i32> %x, zeroinitializer + %negx = sub nsw <2 x i32> zeroinitializer, %x + %abs = select <2 x i1> %cmp, <2 x i32> %negx, <2 x i32> %x + %r = icmp slt <2 x i32> %abs, <i32 -8, i32 -8> + ret <2 x i1> %r +} + +; Equality predicates are ok. + +define i1 @nabs_is_negative_or_0_ne(i8 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_ne( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i8 %x, 0 + %negx = sub i8 0, %x + %nabs = select i1 %cmp, i8 %x, i8 %negx + %r = icmp ne i8 %nabs, 12 + ret i1 %r +} + +; Vector types are ok. + +define <3 x i1> @nabs_is_not_over_0_sle_vec_splat(<3 x i33> %x) { +; CHECK-LABEL: @nabs_is_not_over_0_sle_vec_splat( +; CHECK-NEXT: ret <3 x i1> zeroinitializer +; + %cmp = icmp slt <3 x i33> %x, <i33 1, i33 1, i33 1> + %negx = sub <3 x i33> zeroinitializer, %x + %nabs = select <3 x i1> %cmp, <3 x i33> %x, <3 x i33> %negx + %r = icmp sge <3 x i33> %nabs, <i33 1, i33 1, i33 1> + ret <3 x i1> %r +} + +; Negative test - intersection does not equal absolute value range. +; PR39510 - https://bugs.llvm.org/show_bug.cgi?id=39510 + +define i1 @abs_no_intersection(i32 %a) { +; CHECK-LABEL: @abs_no_intersection( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[A]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[A]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[COND]], 2 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %a, 0 + %sub = sub nsw i32 0, %a + %cond = select i1 %cmp, i32 %sub, i32 %a + %r = icmp ne i32 %cond, 2 + ret i1 %r +} + +; Negative test - intersection does not equal absolute value range. + +define i1 @nabs_no_intersection(i32 %a) { +; CHECK-LABEL: @nabs_no_intersection( +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[SUB:%.*]] = sub i32 0, [[A]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[A]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[COND]], -2 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp sgt i32 %a, 0 + %sub = sub i32 0, %a + %cond = select i1 %cmp, i32 %sub, i32 %a + %r = icmp ne i32 %cond, -2 + ret i1 %r +} + diff --git a/llvm/test/Transforms/InstSimplify/icmp-bool-constant.ll b/llvm/test/Transforms/InstSimplify/icmp-bool-constant.ll new file mode 100644 index 00000000000..0b7a8297c68 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/icmp-bool-constant.ll @@ -0,0 +1,196 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; Test all integer predicates with bool types and true/false constants. +; Use vectors to provide test coverage that is not duplicated in other folds. + +define <2 x i1> @eq_t(<2 x i1> %a) { +; CHECK-LABEL: @eq_t( +; CHECK-NEXT: ret <2 x i1> %a +; + %r = icmp eq <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @eq_t_undef_elt(<2 x i1> %a) { +; CHECK-LABEL: @eq_t_undef_elt( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %r = icmp eq <2 x i1> %a, <i1 undef, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @eq_f(<2 x i1> %a) { +; CHECK-LABEL: @eq_f( +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i1> %a, zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %r = icmp eq <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @ne_t(<2 x i1> %a) { +; CHECK-LABEL: @ne_t( +; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i1> %a, <i1 true, i1 true> +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %r = icmp ne <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @ne_f(<2 x i1> %a) { +; CHECK-LABEL: @ne_f( +; CHECK-NEXT: ret <2 x i1> %a +; + %r = icmp ne <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @ugt_t(<2 x i1> %a) { +; CHECK-LABEL: @ugt_t( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %r = icmp ugt <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @ugt_t_undef_elt(<2 x i1> %a) { +; CHECK-LABEL: @ugt_t_undef_elt( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %r = icmp ugt <2 x i1> %a, <i1 true, i1 undef> + ret <2 x i1> %r +} + +define <2 x i1> @ugt_f(<2 x i1> %a) { +; CHECK-LABEL: @ugt_f( +; CHECK-NEXT: ret <2 x i1> %a +; + %r = icmp ugt <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @ult_t(<2 x i1> %a) { +; CHECK-LABEL: @ult_t( +; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i1> %a, <i1 true, i1 true> +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %r = icmp ult <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @ult_f(<2 x i1> %a) { +; CHECK-LABEL: @ult_f( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %r = icmp ult <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @sgt_t(<2 x i1> %a) { +; CHECK-LABEL: @sgt_t( +; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i1> %a, <i1 true, i1 true> +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %r = icmp sgt <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @sgt_f(<2 x i1> %a) { +; CHECK-LABEL: @sgt_f( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %r = icmp sgt <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @slt_t(<2 x i1> %a) { +; CHECK-LABEL: @slt_t( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %r = icmp slt <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @slt_f(<2 x i1> %a) { +; CHECK-LABEL: @slt_f( +; CHECK-NEXT: ret <2 x i1> %a +; + %r = icmp slt <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @uge_t(<2 x i1> %a) { +; CHECK-LABEL: @uge_t( +; CHECK-NEXT: ret <2 x i1> %a +; + %r = icmp uge <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @uge_f(<2 x i1> %a) { +; CHECK-LABEL: @uge_f( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %r = icmp uge <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @ule_t(<2 x i1> %a) { +; CHECK-LABEL: @ule_t( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %r = icmp ule <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @ule_f(<2 x i1> %a) { +; CHECK-LABEL: @ule_f( +; CHECK-NEXT: [[R:%.*]] = icmp ule <2 x i1> %a, zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %r = icmp ule <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @sge_t(<2 x i1> %a) { +; CHECK-LABEL: @sge_t( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %r = icmp sge <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @sge_t_undef_elt(<2 x i1> %a) { +; CHECK-LABEL: @sge_t_undef_elt( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %r = icmp sge <2 x i1> %a, <i1 true, i1 undef> + ret <2 x i1> %r +} + +define <2 x i1> @sge_f(<2 x i1> %a) { +; CHECK-LABEL: @sge_f( +; CHECK-NEXT: [[R:%.*]] = icmp sge <2 x i1> %a, zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %r = icmp sge <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + +define <2 x i1> @sle_t(<2 x i1> %a) { +; CHECK-LABEL: @sle_t( +; CHECK-NEXT: ret <2 x i1> %a +; + %r = icmp sle <2 x i1> %a, <i1 true, i1 true> + ret <2 x i1> %r +} + +define <2 x i1> @sle_f(<2 x i1> %a) { +; CHECK-LABEL: @sle_f( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %r = icmp sle <2 x i1> %a, <i1 false, i1 false> + ret <2 x i1> %r +} + diff --git a/llvm/test/Transforms/InstSimplify/icmp-constant.ll b/llvm/test/Transforms/InstSimplify/icmp-constant.ll new file mode 100644 index 00000000000..3ebaca7c8aa --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/icmp-constant.ll @@ -0,0 +1,760 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; Fold icmp with a constant operand. + +define i1 @tautological_ule(i8 %x) { +; CHECK-LABEL: @tautological_ule( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp ule i8 %x, 255 + ret i1 %cmp +} + +define <2 x i1> @tautological_ule_vec(<2 x i8> %x) { +; CHECK-LABEL: @tautological_ule_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %cmp = icmp ule <2 x i8> %x, <i8 255, i8 255> + ret <2 x i1> %cmp +} + +define i1 @tautological_ugt(i8 %x) { +; CHECK-LABEL: @tautological_ugt( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp ugt i8 %x, 255 + ret i1 %cmp +} + +define <2 x i1> @tautological_ugt_vec(<2 x i8> %x) { +; CHECK-LABEL: @tautological_ugt_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %cmp = icmp ugt <2 x i8> %x, <i8 255, i8 255> + ret <2 x i1> %cmp +} + +; 'urem x, C2' produces [0, C2) +define i1 @urem3(i32 %X) { +; CHECK-LABEL: @urem3( +; CHECK-NEXT: ret i1 true +; + %A = urem i32 %X, 10 + %B = icmp ult i32 %A, 15 + ret i1 %B +} + +define <2 x i1> @urem3_vec(<2 x i32> %X) { +; CHECK-LABEL: @urem3_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %A = urem <2 x i32> %X, <i32 10, i32 10> + %B = icmp ult <2 x i32> %A, <i32 15, i32 15> + ret <2 x i1> %B +} + +;'srem x, C2' produces (-|C2|, |C2|) +define i1 @srem1(i32 %X) { +; CHECK-LABEL: @srem1( +; CHECK-NEXT: ret i1 false +; + %A = srem i32 %X, -5 + %B = icmp sgt i32 %A, 5 + ret i1 %B +} + +define <2 x i1> @srem1_vec(<2 x i32> %X) { +; CHECK-LABEL: @srem1_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %A = srem <2 x i32> %X, <i32 -5, i32 -5> + %B = icmp sgt <2 x i32> %A, <i32 5, i32 5> + ret <2 x i1> %B +} + +;'udiv C2, x' produces [0, C2] +define i1 @udiv5(i32 %X) { +; CHECK-LABEL: @udiv5( +; CHECK-NEXT: ret i1 false +; + %A = udiv i32 123, %X + %C = icmp ugt i32 %A, 124 + ret i1 %C +} + +define <2 x i1> @udiv5_vec(<2 x i32> %X) { +; CHECK-LABEL: @udiv5_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %A = udiv <2 x i32> <i32 123, i32 123>, %X + %C = icmp ugt <2 x i32> %A, <i32 124, i32 124> + ret <2 x i1> %C +} + +; 'udiv x, C2' produces [0, UINT_MAX / C2] +define i1 @udiv1(i32 %X) { +; CHECK-LABEL: @udiv1( +; CHECK-NEXT: ret i1 true +; + %A = udiv i32 %X, 1000000 + %B = icmp ult i32 %A, 5000 + ret i1 %B +} + +define <2 x i1> @udiv1_vec(<2 x i32> %X) { +; CHECK-LABEL: @udiv1_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %A = udiv <2 x i32> %X, <i32 1000000, i32 1000000> + %B = icmp ult <2 x i32> %A, <i32 5000, i32 5000> + ret <2 x i1> %B +} + +; 'sdiv C2, x' produces [-|C2|, |C2|] +define i1 @compare_dividend(i32 %a) { +; CHECK-LABEL: @compare_dividend( +; CHECK-NEXT: ret i1 false +; + %div = sdiv i32 2, %a + %cmp = icmp eq i32 %div, 3 + ret i1 %cmp +} + +define <2 x i1> @compare_dividend_vec(<2 x i32> %a) { +; CHECK-LABEL: @compare_dividend_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %div = sdiv <2 x i32> <i32 2, i32 2>, %a + %cmp = icmp eq <2 x i32> %div, <i32 3, i32 3> + ret <2 x i1> %cmp +} + +; 'sdiv x, C2' produces [INT_MIN / C2, INT_MAX / C2] +; where C2 != -1 and C2 != 0 and C2 != 1 +define i1 @sdiv1(i32 %X) { +; CHECK-LABEL: @sdiv1( +; CHECK-NEXT: ret i1 true +; + %A = sdiv i32 %X, 1000000 + %B = icmp slt i32 %A, 3000 + ret i1 %B +} + +define <2 x i1> @sdiv1_vec(<2 x i32> %X) { +; CHECK-LABEL: @sdiv1_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %A = sdiv <2 x i32> %X, <i32 1000000, i32 1000000> + %B = icmp slt <2 x i32> %A, <i32 3000, i32 3000> + ret <2 x i1> %B +} + +; 'shl nuw C2, x' produces [C2, C2 << CLZ(C2)] +define i1 @shl5(i32 %X) { +; CHECK-LABEL: @shl5( +; CHECK-NEXT: ret i1 true +; + %sub = shl nuw i32 4, %X + %cmp = icmp ugt i32 %sub, 3 + ret i1 %cmp +} + +define <2 x i1> @shl5_vec(<2 x i32> %X) { +; CHECK-LABEL: @shl5_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %sub = shl nuw <2 x i32> <i32 4, i32 4>, %X + %cmp = icmp ugt <2 x i32> %sub, <i32 3, i32 3> + ret <2 x i1> %cmp +} + +; 'shl nsw C2, x' produces [C2 << CLO(C2)-1, C2] +define i1 @shl2(i32 %X) { +; CHECK-LABEL: @shl2( +; CHECK-NEXT: ret i1 false +; + %sub = shl nsw i32 -1, %X + %cmp = icmp eq i32 %sub, 31 + ret i1 %cmp +} + +define <2 x i1> @shl2_vec(<2 x i32> %X) { +; CHECK-LABEL: @shl2_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %sub = shl nsw <2 x i32> <i32 -1, i32 -1>, %X + %cmp = icmp eq <2 x i32> %sub, <i32 31, i32 31> + ret <2 x i1> %cmp +} + +; 'shl nsw C2, x' produces [C2 << CLO(C2)-1, C2] +define i1 @shl4(i32 %X) { +; CHECK-LABEL: @shl4( +; CHECK-NEXT: ret i1 true +; + %sub = shl nsw i32 -1, %X + %cmp = icmp sle i32 %sub, -1 + ret i1 %cmp +} + +define <2 x i1> @shl4_vec(<2 x i32> %X) { +; CHECK-LABEL: @shl4_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %sub = shl nsw <2 x i32> <i32 -1, i32 -1>, %X + %cmp = icmp sle <2 x i32> %sub, <i32 -1, i32 -1> + ret <2 x i1> %cmp +} + +; 'shl nsw C2, x' produces [C2, C2 << CLZ(C2)-1] +define i1 @icmp_shl_nsw_1(i64 %a) { +; CHECK-LABEL: @icmp_shl_nsw_1( +; CHECK-NEXT: ret i1 true +; + %shl = shl nsw i64 1, %a + %cmp = icmp sge i64 %shl, 0 + ret i1 %cmp +} + +define <2 x i1> @icmp_shl_nsw_1_vec(<2 x i64> %a) { +; CHECK-LABEL: @icmp_shl_nsw_1_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %shl = shl nsw <2 x i64> <i64 1, i64 1>, %a + %cmp = icmp sge <2 x i64> %shl, zeroinitializer + ret <2 x i1> %cmp +} + +; 'shl nsw C2, x' produces [C2 << CLO(C2)-1, C2] +define i1 @icmp_shl_nsw_neg1(i64 %a) { +; CHECK-LABEL: @icmp_shl_nsw_neg1( +; CHECK-NEXT: ret i1 false +; + %shl = shl nsw i64 -1, %a + %cmp = icmp sge i64 %shl, 3 + ret i1 %cmp +} + +define <2 x i1> @icmp_shl_nsw_neg1_vec(<2 x i64> %a) { +; CHECK-LABEL: @icmp_shl_nsw_neg1_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %shl = shl nsw <2 x i64> <i64 -1, i64 -1>, %a + %cmp = icmp sge <2 x i64> %shl, <i64 3, i64 3> + ret <2 x i1> %cmp +} + +; 'lshr x, C2' produces [0, UINT_MAX >> C2] +define i1 @lshr2(i32 %x) { +; CHECK-LABEL: @lshr2( +; CHECK-NEXT: ret i1 false +; + %s = lshr i32 %x, 30 + %c = icmp ugt i32 %s, 8 + ret i1 %c +} + +define <2 x i1> @lshr2_vec(<2 x i32> %x) { +; CHECK-LABEL: @lshr2_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %s = lshr <2 x i32> %x, <i32 30, i32 30> + %c = icmp ugt <2 x i32> %s, <i32 8, i32 8> + ret <2 x i1> %c +} + +; 'lshr C2, x' produces [C2 >> (Width-1), C2] +define i1 @exact_lshr_ugt_false(i32 %a) { +; CHECK-LABEL: @exact_lshr_ugt_false( +; CHECK-NEXT: ret i1 false +; + %shr = lshr exact i32 30, %a + %cmp = icmp ult i32 %shr, 15 + ret i1 %cmp +} + +define <2 x i1> @exact_lshr_ugt_false_vec(<2 x i32> %a) { +; CHECK-LABEL: @exact_lshr_ugt_false_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %shr = lshr exact <2 x i32> <i32 30, i32 30>, %a + %cmp = icmp ult <2 x i32> %shr, <i32 15, i32 15> + ret <2 x i1> %cmp +} + +; 'lshr C2, x' produces [C2 >> (Width-1), C2] +define i1 @lshr_sgt_false(i32 %a) { +; CHECK-LABEL: @lshr_sgt_false( +; CHECK-NEXT: ret i1 false +; + %shr = lshr i32 1, %a + %cmp = icmp sgt i32 %shr, 1 + ret i1 %cmp +} + +define <2 x i1> @lshr_sgt_false_vec(<2 x i32> %a) { +; CHECK-LABEL: @lshr_sgt_false_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %shr = lshr <2 x i32> <i32 1, i32 1>, %a + %cmp = icmp sgt <2 x i32> %shr, <i32 1, i32 1> + ret <2 x i1> %cmp +} + +; 'ashr x, C2' produces [INT_MIN >> C2, INT_MAX >> C2] +define i1 @ashr2(i32 %x) { +; CHECK-LABEL: @ashr2( +; CHECK-NEXT: ret i1 false +; + %s = ashr i32 %x, 30 + %c = icmp slt i32 %s, -5 + ret i1 %c +} + +define <2 x i1> @ashr2_vec(<2 x i32> %x) { +; CHECK-LABEL: @ashr2_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %s = ashr <2 x i32> %x, <i32 30, i32 30> + %c = icmp slt <2 x i32> %s, <i32 -5, i32 -5> + ret <2 x i1> %c +} + +; 'ashr C2, x' produces [C2, C2 >> (Width-1)] +define i1 @ashr_sgt_false(i32 %a) { +; CHECK-LABEL: @ashr_sgt_false( +; CHECK-NEXT: ret i1 false +; + %shr = ashr i32 -30, %a + %cmp = icmp sgt i32 %shr, -1 + ret i1 %cmp +} + +define <2 x i1> @ashr_sgt_false_vec(<2 x i32> %a) { +; CHECK-LABEL: @ashr_sgt_false_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %shr = ashr <2 x i32> <i32 -30, i32 -30>, %a + %cmp = icmp sgt <2 x i32> %shr, <i32 -1, i32 -1> + ret <2 x i1> %cmp +} + +; 'ashr C2, x' produces [C2, C2 >> (Width-1)] +define i1 @exact_ashr_sgt_false(i32 %a) { +; CHECK-LABEL: @exact_ashr_sgt_false( +; CHECK-NEXT: ret i1 false +; + %shr = ashr exact i32 -30, %a + %cmp = icmp sgt i32 %shr, -15 + ret i1 %cmp +} + +define <2 x i1> @exact_ashr_sgt_false_vec(<2 x i32> %a) { +; CHECK-LABEL: @exact_ashr_sgt_false_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %shr = ashr exact <2 x i32> <i32 -30, i32 -30>, %a + %cmp = icmp sgt <2 x i32> %shr, <i32 -15, i32 -15> + ret <2 x i1> %cmp +} + +; 'or x, C2' produces [C2, UINT_MAX] +define i1 @or1(i32 %X) { +; CHECK-LABEL: @or1( +; CHECK-NEXT: ret i1 false +; + %A = or i32 %X, 62 + %B = icmp ult i32 %A, 50 + ret i1 %B +} + +define <2 x i1> @or1_vec(<2 x i32> %X) { +; CHECK-LABEL: @or1_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %A = or <2 x i32> %X, <i32 62, i32 62> + %B = icmp ult <2 x i32> %A, <i32 50, i32 50> + ret <2 x i1> %B +} + +; Single bit OR. +define i1 @or2_true(i8 %x) { +; CHECK-LABEL: @or2_true( +; CHECK-NEXT: [[Y:%.*]] = or i8 [[X:%.*]], 64 +; CHECK-NEXT: [[Z:%.*]] = icmp sge i8 [[Y]], -64 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = or i8 %x, 64 + %z = icmp sge i8 %y, -64 + ret i1 %z +} + +define i1 @or2_unknown(i8 %x) { +; CHECK-LABEL: @or2_unknown( +; CHECK-NEXT: [[Y:%.*]] = or i8 [[X:%.*]], 64 +; CHECK-NEXT: [[Z:%.*]] = icmp sgt i8 [[Y]], -64 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = or i8 %x, 64 + %z = icmp sgt i8 %y, -64 + ret i1 %z +} + +; Multi bit OR. +; 78 = 0b01001110; -50 = 0b11001110 +define i1 @or3_true(i8 %x) { +; CHECK-LABEL: @or3_true( +; CHECK-NEXT: [[Y:%.*]] = or i8 [[X:%.*]], 78 +; CHECK-NEXT: [[Z:%.*]] = icmp sge i8 [[Y]], -50 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = or i8 %x, 78 + %z = icmp sge i8 %y, -50 + ret i1 %z +} + +define i1 @or3_unknown(i8 %x) { +; CHECK-LABEL: @or3_unknown( +; CHECK-NEXT: [[Y:%.*]] = or i8 [[X:%.*]], 78 +; CHECK-NEXT: [[Z:%.*]] = icmp sgt i8 [[Y]], -50 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = or i8 %x, 78 + %z = icmp sgt i8 %y, -50 + ret i1 %z +} + +; OR with sign bit. +define i1 @or4_true(i8 %x) { +; CHECK-LABEL: @or4_true( +; CHECK-NEXT: ret i1 true +; + %y = or i8 %x, -64 + %z = icmp sge i8 %y, -64 + ret i1 %z +} + +define i1 @or4_unknown(i8 %x) { +; CHECK-LABEL: @or4_unknown( +; CHECK-NEXT: [[Y:%.*]] = or i8 [[X:%.*]], -64 +; CHECK-NEXT: [[Z:%.*]] = icmp sgt i8 [[Y]], -64 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = or i8 %x, -64 + %z = icmp sgt i8 %y, -64 + ret i1 %z +} + +; If sign bit is set, signed & unsigned ranges are the same. +define i1 @or5_true(i8 %x) { +; CHECK-LABEL: @or5_true( +; CHECK-NEXT: ret i1 true +; + %y = or i8 %x, -64 + %z = icmp uge i8 %y, -64 + ret i1 %z +} + +define i1 @or5_unknown(i8 %x) { +; CHECK-LABEL: @or5_unknown( +; CHECK-NEXT: [[Y:%.*]] = or i8 [[X:%.*]], -64 +; CHECK-NEXT: [[Z:%.*]] = icmp ugt i8 [[Y]], -64 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = or i8 %x, -64 + %z = icmp ugt i8 %y, -64 + ret i1 %z +} + +; 'and x, C2' produces [0, C2] +define i1 @and1(i32 %X) { +; CHECK-LABEL: @and1( +; CHECK-NEXT: ret i1 false +; + %A = and i32 %X, 62 + %B = icmp ugt i32 %A, 70 + ret i1 %B +} + +define <2 x i1> @and1_vec(<2 x i32> %X) { +; CHECK-LABEL: @and1_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %A = and <2 x i32> %X, <i32 62, i32 62> + %B = icmp ugt <2 x i32> %A, <i32 70, i32 70> + ret <2 x i1> %B +} + +; If the sign bit is not set, signed and unsigned ranges are the same. +define i1 @and2(i32 %X) { +; CHECK-LABEL: @and2( +; CHECK-NEXT: ret i1 false +; + %A = and i32 %X, 62 + %B = icmp sgt i32 %A, 70 + ret i1 %B +} + +; -75 = 0b10110101, 53 = 0b00110101 +define i1 @and3_true1(i8 %x) { +; CHECK-LABEL: @and3_true1( +; CHECK-NEXT: [[Y:%.*]] = and i8 [[X:%.*]], -75 +; CHECK-NEXT: [[Z:%.*]] = icmp sge i8 [[Y]], -75 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = and i8 %x, -75 + %z = icmp sge i8 %y, -75 + ret i1 %z +} + +define i1 @and3_unknown1(i8 %x) { +; CHECK-LABEL: @and3_unknown1( +; CHECK-NEXT: [[Y:%.*]] = and i8 [[X:%.*]], -75 +; CHECK-NEXT: [[Z:%.*]] = icmp sgt i8 [[Y]], -75 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = and i8 %x, -75 + %z = icmp sgt i8 %y, -75 + ret i1 %z +} + +define i1 @and3_true2(i8 %x) { +; CHECK-LABEL: @and3_true2( +; CHECK-NEXT: [[Y:%.*]] = and i8 [[X:%.*]], -75 +; CHECK-NEXT: [[Z:%.*]] = icmp sle i8 [[Y]], 53 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = and i8 %x, -75 + %z = icmp sle i8 %y, 53 + ret i1 %z +} + +define i1 @and3_unknown2(i8 %x) { +; CHECK-LABEL: @and3_unknown2( +; CHECK-NEXT: [[Y:%.*]] = and i8 [[X:%.*]], -75 +; CHECK-NEXT: [[Z:%.*]] = icmp slt i8 [[Y]], 53 +; CHECK-NEXT: ret i1 [[Z]] +; + %y = and i8 %x, -75 + %z = icmp slt i8 %y, 53 + ret i1 %z +} + +; 'add nuw x, C2' produces [C2, UINT_MAX] +define i1 @tautological9(i32 %x) { +; CHECK-LABEL: @tautological9( +; CHECK-NEXT: ret i1 true +; + %add = add nuw i32 %x, 13 + %cmp = icmp ne i32 %add, 12 + ret i1 %cmp +} + +define <2 x i1> @tautological9_vec(<2 x i32> %x) { +; CHECK-LABEL: @tautological9_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %add = add nuw <2 x i32> %x, <i32 13, i32 13> + %cmp = icmp ne <2 x i32> %add, <i32 12, i32 12> + ret <2 x i1> %cmp +} + +; The upper bound of the 'add' is 0. + +define i1 @add_nsw_neg_const1(i32 %x) { +; CHECK-LABEL: @add_nsw_neg_const1( +; CHECK-NEXT: ret i1 false +; + %add = add nsw i32 %x, -2147483647 + %cmp = icmp sgt i32 %add, 0 + ret i1 %cmp +} + +; InstCombine can fold this, but not InstSimplify. + +define i1 @add_nsw_neg_const2(i32 %x) { +; CHECK-LABEL: @add_nsw_neg_const2( +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], -2147483647 +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ADD]], -1 +; CHECK-NEXT: ret i1 [[CMP]] +; + %add = add nsw i32 %x, -2147483647 + %cmp = icmp sgt i32 %add, -1 + ret i1 %cmp +} + +; The upper bound of the 'add' is 1 (move the constants to prove we're doing range-based analysis). + +define i1 @add_nsw_neg_const3(i32 %x) { +; CHECK-LABEL: @add_nsw_neg_const3( +; CHECK-NEXT: ret i1 false +; + %add = add nsw i32 %x, -2147483646 + %cmp = icmp sgt i32 %add, 1 + ret i1 %cmp +} + +; InstCombine can fold this, but not InstSimplify. + +define i1 @add_nsw_neg_const4(i32 %x) { +; CHECK-LABEL: @add_nsw_neg_const4( +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], -2147483646 +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ADD]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +; + %add = add nsw i32 %x, -2147483646 + %cmp = icmp sgt i32 %add, 0 + ret i1 %cmp +} + +; The upper bound of the 'add' is 2147483647 - 42 = 2147483605 (move the constants again and try a different cmp predicate). + +define i1 @add_nsw_neg_const5(i32 %x) { +; CHECK-LABEL: @add_nsw_neg_const5( +; CHECK-NEXT: ret i1 true +; + %add = add nsw i32 %x, -42 + %cmp = icmp ne i32 %add, 2147483606 + ret i1 %cmp +} + +; InstCombine can fold this, but not InstSimplify. + +define i1 @add_nsw_neg_const6(i32 %x) { +; CHECK-LABEL: @add_nsw_neg_const6( +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], -42 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[ADD]], 2147483605 +; CHECK-NEXT: ret i1 [[CMP]] +; + %add = add nsw i32 %x, -42 + %cmp = icmp ne i32 %add, 2147483605 + ret i1 %cmp +} + +; The lower bound of the 'add' is -1. + +define i1 @add_nsw_pos_const1(i32 %x) { +; CHECK-LABEL: @add_nsw_pos_const1( +; CHECK-NEXT: ret i1 false +; + %add = add nsw i32 %x, 2147483647 + %cmp = icmp slt i32 %add, -1 + ret i1 %cmp +} + +; InstCombine can fold this, but not InstSimplify. + +define i1 @add_nsw_pos_const2(i32 %x) { +; CHECK-LABEL: @add_nsw_pos_const2( +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], 2147483647 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +; + %add = add nsw i32 %x, 2147483647 + %cmp = icmp slt i32 %add, 0 + ret i1 %cmp +} + +; The lower bound of the 'add' is -2 (move the constants to prove we're doing range-based analysis). + +define i1 @add_nsw_pos_const3(i32 %x) { +; CHECK-LABEL: @add_nsw_pos_const3( +; CHECK-NEXT: ret i1 false +; + %add = add nsw i32 %x, 2147483646 + %cmp = icmp slt i32 %add, -2 + ret i1 %cmp +} + +; InstCombine can fold this, but not InstSimplify. + +define i1 @add_nsw_pos_const4(i32 %x) { +; CHECK-LABEL: @add_nsw_pos_const4( +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], 2147483646 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD]], -1 +; CHECK-NEXT: ret i1 [[CMP]] +; + %add = add nsw i32 %x, 2147483646 + %cmp = icmp slt i32 %add, -1 + ret i1 %cmp +} + +; The lower bound of the 'add' is -2147483648 + 42 = -2147483606 (move the constants again and change the cmp predicate). + +define i1 @add_nsw_pos_const5(i32 %x) { +; CHECK-LABEL: @add_nsw_pos_const5( +; CHECK-NEXT: ret i1 false +; + %add = add nsw i32 %x, 42 + %cmp = icmp eq i32 %add, -2147483607 + ret i1 %cmp +} + +; InstCombine can fold this, but not InstSimplify. + +define i1 @add_nsw_pos_const6(i32 %x) { +; CHECK-LABEL: @add_nsw_pos_const6( +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], 42 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[ADD]], -2147483606 +; CHECK-NEXT: ret i1 [[CMP]] +; + %add = add nsw i32 %x, 42 + %cmp = icmp eq i32 %add, -2147483606 + ret i1 %cmp +} + +; Verify that vectors work too. + +define <2 x i1> @add_nsw_pos_const5_splat_vec(<2 x i32> %x) { +; CHECK-LABEL: @add_nsw_pos_const5_splat_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %add = add nsw <2 x i32> %x, <i32 42, i32 42> + %cmp = icmp ne <2 x i32> %add, <i32 -2147483607, i32 -2147483607> + ret <2 x i1> %cmp +} + +; PR34838 - https://bugs.llvm.org/show_bug.cgi?id=34838 +; The shift is known to create poison, so we can simplify the cmp. + +define i1 @ne_shl_by_constant_produces_poison(i8 %x) { +; CHECK-LABEL: @ne_shl_by_constant_produces_poison( +; CHECK-NEXT: ret i1 true +; + %zx = zext i8 %x to i16 ; zx = 0x00xx + %xor = xor i16 %zx, 32767 ; xor = 0x7fyy + %sub = sub nsw i16 %zx, %xor ; sub = 0x80zz (the top bit is known one) + %poison = shl nsw i16 %sub, 2 ; oops! this shl can't be nsw; that's POISON + %cmp = icmp ne i16 %poison, 1 + ret i1 %cmp +} + +define i1 @eq_shl_by_constant_produces_poison(i8 %x) { +; CHECK-LABEL: @eq_shl_by_constant_produces_poison( +; CHECK-NEXT: ret i1 false +; + %clear_high_bit = and i8 %x, 127 ; 0x7f + %set_next_high_bits = or i8 %clear_high_bit, 112 ; 0x70 + %poison = shl nsw i8 %set_next_high_bits, 3 + %cmp = icmp eq i8 %poison, 15 + ret i1 %cmp +} + +; Shift-by-variable that produces poison is more complicated but still possible. +; We guarantee that the shift will change the sign of the shifted value (and +; therefore produce poison) by limiting its range from 1 to 3. + +define i1 @eq_shl_by_variable_produces_poison(i8 %x) { +; CHECK-LABEL: @eq_shl_by_variable_produces_poison( +; CHECK-NEXT: ret i1 false +; + %clear_high_bit = and i8 %x, 127 ; 0x7f + %set_next_high_bits = or i8 %clear_high_bit, 112 ; 0x70 + %notundef_shiftamt = and i8 %x, 3 + %nonzero_shiftamt = or i8 %notundef_shiftamt, 1 + %poison = shl nsw i8 %set_next_high_bits, %nonzero_shiftamt + %cmp = icmp eq i8 %poison, 15 + ret i1 %cmp +} + diff --git a/llvm/test/Transforms/InstSimplify/icmp-ranges.ll b/llvm/test/Transforms/InstSimplify/icmp-ranges.ll new file mode 100644 index 00000000000..45194f2df4f --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/icmp-ranges.ll @@ -0,0 +1,5470 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; Cycle through all pairs of predicates to test +; simplification of range-intersection or range-union. + +; eq +; x == 13 && x == 17 + +define i1 @and_eq_eq(i8 %x) { +; CHECK-LABEL: @and_eq_eq( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x != 17 + +define i1 @and_eq_ne(i8 %x) { +; CHECK-LABEL: @and_eq_ne( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x >=s 17 + +define i1 @and_eq_sge(i8 %x) { +; CHECK-LABEL: @and_eq_sge( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x >s 17 + +define i1 @and_eq_sgt(i8 %x) { +; CHECK-LABEL: @and_eq_sgt( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x <=s 17 + +define i1 @and_eq_sle(i8 %x) { +; CHECK-LABEL: @and_eq_sle( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x <s 17 + +define i1 @and_eq_slt(i8 %x) { +; CHECK-LABEL: @and_eq_slt( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x >=u 17 + +define i1 @and_eq_uge(i8 %x) { +; CHECK-LABEL: @and_eq_uge( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x >u 17 + +define i1 @and_eq_ugt(i8 %x) { +; CHECK-LABEL: @and_eq_ugt( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x <=u 17 + +define i1 @and_eq_ule(i8 %x) { +; CHECK-LABEL: @and_eq_ule( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 13 && x <u 17 + +define i1 @and_eq_ult(i8 %x) { +; CHECK-LABEL: @and_eq_ult( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ne +; x != 13 && x == 17 + +define i1 @and_ne_eq(i8 %x) { +; CHECK-LABEL: @and_ne_eq( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x != 17 + +define i1 @and_ne_ne(i8 %x) { +; CHECK-LABEL: @and_ne_ne( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x >=s 17 + +define i1 @and_ne_sge(i8 %x) { +; CHECK-LABEL: @and_ne_sge( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x >s 17 + +define i1 @and_ne_sgt(i8 %x) { +; CHECK-LABEL: @and_ne_sgt( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x <=s 17 + +define i1 @and_ne_sle(i8 %x) { +; CHECK-LABEL: @and_ne_sle( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x <s 17 + +define i1 @and_ne_slt(i8 %x) { +; CHECK-LABEL: @and_ne_slt( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x >=u 17 + +define i1 @and_ne_uge(i8 %x) { +; CHECK-LABEL: @and_ne_uge( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x >u 17 + +define i1 @and_ne_ugt(i8 %x) { +; CHECK-LABEL: @and_ne_ugt( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x <=u 17 + +define i1 @and_ne_ule(i8 %x) { +; CHECK-LABEL: @and_ne_ule( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 13 && x <u 17 + +define i1 @and_ne_ult(i8 %x) { +; CHECK-LABEL: @and_ne_ult( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; sge +; x >=s 13 && x == 17 + +define i1 @and_sge_eq(i8 %x) { +; CHECK-LABEL: @and_sge_eq( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x != 17 + +define i1 @and_sge_ne(i8 %x) { +; CHECK-LABEL: @and_sge_ne( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x >=s 17 + +define i1 @and_sge_sge(i8 %x) { +; CHECK-LABEL: @and_sge_sge( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x >s 17 + +define i1 @and_sge_sgt(i8 %x) { +; CHECK-LABEL: @and_sge_sgt( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x <=s 17 + +define i1 @and_sge_sle(i8 %x) { +; CHECK-LABEL: @and_sge_sle( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x <s 17 + +define i1 @and_sge_slt(i8 %x) { +; CHECK-LABEL: @and_sge_slt( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x >=u 17 + +define i1 @and_sge_uge(i8 %x) { +; CHECK-LABEL: @and_sge_uge( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x >u 17 + +define i1 @and_sge_ugt(i8 %x) { +; CHECK-LABEL: @and_sge_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x <=u 17 + +define i1 @and_sge_ule(i8 %x) { +; CHECK-LABEL: @and_sge_ule( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 13 && x <u 17 + +define i1 @and_sge_ult(i8 %x) { +; CHECK-LABEL: @and_sge_ult( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; sgt +; x >s 13 && x == 17 + +define i1 @and_sgt_eq(i8 %x) { +; CHECK-LABEL: @and_sgt_eq( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x != 17 + +define i1 @and_sgt_ne(i8 %x) { +; CHECK-LABEL: @and_sgt_ne( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x >=s 17 + +define i1 @and_sgt_sge(i8 %x) { +; CHECK-LABEL: @and_sgt_sge( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x >s 17 + +define i1 @and_sgt_sgt(i8 %x) { +; CHECK-LABEL: @and_sgt_sgt( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x <=s 17 + +define i1 @and_sgt_sle(i8 %x) { +; CHECK-LABEL: @and_sgt_sle( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x <s 17 + +define i1 @and_sgt_slt(i8 %x) { +; CHECK-LABEL: @and_sgt_slt( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x >=u 17 + +define i1 @and_sgt_uge(i8 %x) { +; CHECK-LABEL: @and_sgt_uge( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x >u 17 + +define i1 @and_sgt_ugt(i8 %x) { +; CHECK-LABEL: @and_sgt_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x <=u 17 + +define i1 @and_sgt_ule(i8 %x) { +; CHECK-LABEL: @and_sgt_ule( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 13 && x <u 17 + +define i1 @and_sgt_ult(i8 %x) { +; CHECK-LABEL: @and_sgt_ult( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; sle +; x <=s 13 && x == 17 + +define i1 @and_sle_eq(i8 %x) { +; CHECK-LABEL: @and_sle_eq( +; CHECK-NEXT: ret i1 false +; + %a = icmp sle i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x != 17 + +define i1 @and_sle_ne(i8 %x) { +; CHECK-LABEL: @and_sle_ne( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x >=s 17 + +define i1 @and_sle_sge(i8 %x) { +; CHECK-LABEL: @and_sle_sge( +; CHECK-NEXT: ret i1 false +; + %a = icmp sle i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x >s 17 + +define i1 @and_sle_sgt(i8 %x) { +; CHECK-LABEL: @and_sle_sgt( +; CHECK-NEXT: ret i1 false +; + %a = icmp sle i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x <=s 17 + +define i1 @and_sle_sle(i8 %x) { +; CHECK-LABEL: @and_sle_sle( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x <s 17 + +define i1 @and_sle_slt(i8 %x) { +; CHECK-LABEL: @and_sle_slt( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x >=u 17 + +define i1 @and_sle_uge(i8 %x) { +; CHECK-LABEL: @and_sle_uge( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x >u 17 + +define i1 @and_sle_ugt(i8 %x) { +; CHECK-LABEL: @and_sle_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x <=u 17 + +define i1 @and_sle_ule(i8 %x) { +; CHECK-LABEL: @and_sle_ule( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 13 && x <u 17 + +define i1 @and_sle_ult(i8 %x) { +; CHECK-LABEL: @and_sle_ult( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; slt +; x <s 13 && x == 17 + +define i1 @and_slt_eq(i8 %x) { +; CHECK-LABEL: @and_slt_eq( +; CHECK-NEXT: ret i1 false +; + %a = icmp slt i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x != 17 + +define i1 @and_slt_ne(i8 %x) { +; CHECK-LABEL: @and_slt_ne( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x >=s 17 + +define i1 @and_slt_sge(i8 %x) { +; CHECK-LABEL: @and_slt_sge( +; CHECK-NEXT: ret i1 false +; + %a = icmp slt i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x >s 17 + +define i1 @and_slt_sgt(i8 %x) { +; CHECK-LABEL: @and_slt_sgt( +; CHECK-NEXT: ret i1 false +; + %a = icmp slt i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x <=s 17 + +define i1 @and_slt_sle(i8 %x) { +; CHECK-LABEL: @and_slt_sle( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x <s 17 + +define i1 @and_slt_slt(i8 %x) { +; CHECK-LABEL: @and_slt_slt( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x >=u 17 + +define i1 @and_slt_uge(i8 %x) { +; CHECK-LABEL: @and_slt_uge( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x >u 17 + +define i1 @and_slt_ugt(i8 %x) { +; CHECK-LABEL: @and_slt_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x <=u 17 + +define i1 @and_slt_ule(i8 %x) { +; CHECK-LABEL: @and_slt_ule( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 13 && x <u 17 + +define i1 @and_slt_ult(i8 %x) { +; CHECK-LABEL: @and_slt_ult( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; uge +; x >=u 13 && x == 17 + +define i1 @and_uge_eq(i8 %x) { +; CHECK-LABEL: @and_uge_eq( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x != 17 + +define i1 @and_uge_ne(i8 %x) { +; CHECK-LABEL: @and_uge_ne( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x >=s 17 + +define i1 @and_uge_sge(i8 %x) { +; CHECK-LABEL: @and_uge_sge( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x >s 17 + +define i1 @and_uge_sgt(i8 %x) { +; CHECK-LABEL: @and_uge_sgt( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x <=s 17 + +define i1 @and_uge_sle(i8 %x) { +; CHECK-LABEL: @and_uge_sle( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x <s 17 + +define i1 @and_uge_slt(i8 %x) { +; CHECK-LABEL: @and_uge_slt( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x >=u 17 + +define i1 @and_uge_uge(i8 %x) { +; CHECK-LABEL: @and_uge_uge( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x >u 17 + +define i1 @and_uge_ugt(i8 %x) { +; CHECK-LABEL: @and_uge_ugt( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x <=u 17 + +define i1 @and_uge_ule(i8 %x) { +; CHECK-LABEL: @and_uge_ule( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 13 && x <u 17 + +define i1 @and_uge_ult(i8 %x) { +; CHECK-LABEL: @and_uge_ult( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ugt +; x >u 13 && x == 17 + +define i1 @and_ugt_eq(i8 %x) { +; CHECK-LABEL: @and_ugt_eq( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x != 17 + +define i1 @and_ugt_ne(i8 %x) { +; CHECK-LABEL: @and_ugt_ne( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x >=s 17 + +define i1 @and_ugt_sge(i8 %x) { +; CHECK-LABEL: @and_ugt_sge( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x >s 17 + +define i1 @and_ugt_sgt(i8 %x) { +; CHECK-LABEL: @and_ugt_sgt( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x <=s 17 + +define i1 @and_ugt_sle(i8 %x) { +; CHECK-LABEL: @and_ugt_sle( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x <s 17 + +define i1 @and_ugt_slt(i8 %x) { +; CHECK-LABEL: @and_ugt_slt( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x >=u 17 + +define i1 @and_ugt_uge(i8 %x) { +; CHECK-LABEL: @and_ugt_uge( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x >u 17 + +define i1 @and_ugt_ugt(i8 %x) { +; CHECK-LABEL: @and_ugt_ugt( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x <=u 17 + +define i1 @and_ugt_ule(i8 %x) { +; CHECK-LABEL: @and_ugt_ule( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 13 && x <u 17 + +define i1 @and_ugt_ult(i8 %x) { +; CHECK-LABEL: @and_ugt_ult( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ule +; x <=u 13 && x == 17 + +define i1 @and_ule_eq(i8 %x) { +; CHECK-LABEL: @and_ule_eq( +; CHECK-NEXT: ret i1 false +; + %a = icmp ule i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x != 17 + +define i1 @and_ule_ne(i8 %x) { +; CHECK-LABEL: @and_ule_ne( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x >=s 17 + +define i1 @and_ule_sge(i8 %x) { +; CHECK-LABEL: @and_ule_sge( +; CHECK-NEXT: ret i1 false +; + %a = icmp ule i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x >s 17 + +define i1 @and_ule_sgt(i8 %x) { +; CHECK-LABEL: @and_ule_sgt( +; CHECK-NEXT: ret i1 false +; + %a = icmp ule i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x <=s 17 + +define i1 @and_ule_sle(i8 %x) { +; CHECK-LABEL: @and_ule_sle( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x <s 17 + +define i1 @and_ule_slt(i8 %x) { +; CHECK-LABEL: @and_ule_slt( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x >=u 17 + +define i1 @and_ule_uge(i8 %x) { +; CHECK-LABEL: @and_ule_uge( +; CHECK-NEXT: ret i1 false +; + %a = icmp ule i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x >u 17 + +define i1 @and_ule_ugt(i8 %x) { +; CHECK-LABEL: @and_ule_ugt( +; CHECK-NEXT: ret i1 false +; + %a = icmp ule i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x <=u 17 + +define i1 @and_ule_ule(i8 %x) { +; CHECK-LABEL: @and_ule_ule( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 13 && x <u 17 + +define i1 @and_ule_ult(i8 %x) { +; CHECK-LABEL: @and_ule_ult( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ult +; x <u 13 && x == 17 + +define i1 @and_ult_eq(i8 %x) { +; CHECK-LABEL: @and_ult_eq( +; CHECK-NEXT: ret i1 false +; + %a = icmp ult i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x != 17 + +define i1 @and_ult_ne(i8 %x) { +; CHECK-LABEL: @and_ult_ne( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x >=s 17 + +define i1 @and_ult_sge(i8 %x) { +; CHECK-LABEL: @and_ult_sge( +; CHECK-NEXT: ret i1 false +; + %a = icmp ult i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x >s 17 + +define i1 @and_ult_sgt(i8 %x) { +; CHECK-LABEL: @and_ult_sgt( +; CHECK-NEXT: ret i1 false +; + %a = icmp ult i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x <=s 17 + +define i1 @and_ult_sle(i8 %x) { +; CHECK-LABEL: @and_ult_sle( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x <s 17 + +define i1 @and_ult_slt(i8 %x) { +; CHECK-LABEL: @and_ult_slt( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x >=u 17 + +define i1 @and_ult_uge(i8 %x) { +; CHECK-LABEL: @and_ult_uge( +; CHECK-NEXT: ret i1 false +; + %a = icmp ult i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x >u 17 + +define i1 @and_ult_ugt(i8 %x) { +; CHECK-LABEL: @and_ult_ugt( +; CHECK-NEXT: ret i1 false +; + %a = icmp ult i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x <=u 17 + +define i1 @and_ult_ule(i8 %x) { +; CHECK-LABEL: @and_ult_ule( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 13 && x <u 17 + +define i1 @and_ult_ult(i8 %x) { +; CHECK-LABEL: @and_ult_ult( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; eq +; x == 23 && x == 17 + +define i1 @and_eq_eq_swap(i8 %x) { +; CHECK-LABEL: @and_eq_eq_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x != 17 + +define i1 @and_eq_ne_swap(i8 %x) { +; CHECK-LABEL: @and_eq_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x >=s 17 + +define i1 @and_eq_sge_swap(i8 %x) { +; CHECK-LABEL: @and_eq_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x >s 17 + +define i1 @and_eq_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_eq_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x <=s 17 + +define i1 @and_eq_sle_swap(i8 %x) { +; CHECK-LABEL: @and_eq_sle_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x <s 17 + +define i1 @and_eq_slt_swap(i8 %x) { +; CHECK-LABEL: @and_eq_slt_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x >=u 17 + +define i1 @and_eq_uge_swap(i8 %x) { +; CHECK-LABEL: @and_eq_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x >u 17 + +define i1 @and_eq_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_eq_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp eq i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x <=u 17 + +define i1 @and_eq_ule_swap(i8 %x) { +; CHECK-LABEL: @and_eq_ule_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x == 23 && x <u 17 + +define i1 @and_eq_ult_swap(i8 %x) { +; CHECK-LABEL: @and_eq_ult_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp eq i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ne +; x != 23 && x == 17 + +define i1 @and_ne_eq_swap(i8 %x) { +; CHECK-LABEL: @and_ne_eq_swap( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x != 17 + +define i1 @and_ne_ne_swap(i8 %x) { +; CHECK-LABEL: @and_ne_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x >=s 17 + +define i1 @and_ne_sge_swap(i8 %x) { +; CHECK-LABEL: @and_ne_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x >s 17 + +define i1 @and_ne_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_ne_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x <=s 17 + +define i1 @and_ne_sle_swap(i8 %x) { +; CHECK-LABEL: @and_ne_sle_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x <s 17 + +define i1 @and_ne_slt_swap(i8 %x) { +; CHECK-LABEL: @and_ne_slt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x >=u 17 + +define i1 @and_ne_uge_swap(i8 %x) { +; CHECK-LABEL: @and_ne_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x >u 17 + +define i1 @and_ne_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_ne_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ne i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x <=u 17 + +define i1 @and_ne_ule_swap(i8 %x) { +; CHECK-LABEL: @and_ne_ule_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x != 23 && x <u 17 + +define i1 @and_ne_ult_swap(i8 %x) { +; CHECK-LABEL: @and_ne_ult_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ne i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; sge +; x >=s 23 && x == 17 + +define i1 @and_sge_eq_swap(i8 %x) { +; CHECK-LABEL: @and_sge_eq_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sge i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x != 17 + +define i1 @and_sge_ne_swap(i8 %x) { +; CHECK-LABEL: @and_sge_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x >=s 17 + +define i1 @and_sge_sge_swap(i8 %x) { +; CHECK-LABEL: @and_sge_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x >s 17 + +define i1 @and_sge_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_sge_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x <=s 17 + +define i1 @and_sge_sle_swap(i8 %x) { +; CHECK-LABEL: @and_sge_sle_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sge i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x <s 17 + +define i1 @and_sge_slt_swap(i8 %x) { +; CHECK-LABEL: @and_sge_slt_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sge i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x >=u 17 + +define i1 @and_sge_uge_swap(i8 %x) { +; CHECK-LABEL: @and_sge_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x >u 17 + +define i1 @and_sge_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_sge_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x <=u 17 + +define i1 @and_sge_ule_swap(i8 %x) { +; CHECK-LABEL: @and_sge_ule_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sge i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=s 23 && x <u 17 + +define i1 @and_sge_ult_swap(i8 %x) { +; CHECK-LABEL: @and_sge_ult_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sge i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; sgt +; x >s 23 && x == 17 + +define i1 @and_sgt_eq_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_eq_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sgt i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x != 17 + +define i1 @and_sgt_ne_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x >=s 17 + +define i1 @and_sgt_sge_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x >s 17 + +define i1 @and_sgt_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x <=s 17 + +define i1 @and_sgt_sle_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_sle_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sgt i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x <s 17 + +define i1 @and_sgt_slt_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_slt_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sgt i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x >=u 17 + +define i1 @and_sgt_uge_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x >u 17 + +define i1 @and_sgt_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x <=u 17 + +define i1 @and_sgt_ule_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_ule_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sgt i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >s 23 && x <u 17 + +define i1 @and_sgt_ult_swap(i8 %x) { +; CHECK-LABEL: @and_sgt_ult_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp sgt i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; sle +; x <=s 23 && x == 17 + +define i1 @and_sle_eq_swap(i8 %x) { +; CHECK-LABEL: @and_sle_eq_swap( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x != 17 + +define i1 @and_sle_ne_swap(i8 %x) { +; CHECK-LABEL: @and_sle_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x >=s 17 + +define i1 @and_sle_sge_swap(i8 %x) { +; CHECK-LABEL: @and_sle_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x >s 17 + +define i1 @and_sle_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_sle_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x <=s 17 + +define i1 @and_sle_sle_swap(i8 %x) { +; CHECK-LABEL: @and_sle_sle_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x <s 17 + +define i1 @and_sle_slt_swap(i8 %x) { +; CHECK-LABEL: @and_sle_slt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x >=u 17 + +define i1 @and_sle_uge_swap(i8 %x) { +; CHECK-LABEL: @and_sle_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x >u 17 + +define i1 @and_sle_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_sle_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x <=u 17 + +define i1 @and_sle_ule_swap(i8 %x) { +; CHECK-LABEL: @and_sle_ule_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=s 23 && x <u 17 + +define i1 @and_sle_ult_swap(i8 %x) { +; CHECK-LABEL: @and_sle_ult_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; slt +; x <s 23 && x == 17 + +define i1 @and_slt_eq_swap(i8 %x) { +; CHECK-LABEL: @and_slt_eq_swap( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x != 17 + +define i1 @and_slt_ne_swap(i8 %x) { +; CHECK-LABEL: @and_slt_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x >=s 17 + +define i1 @and_slt_sge_swap(i8 %x) { +; CHECK-LABEL: @and_slt_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x >s 17 + +define i1 @and_slt_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_slt_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x <=s 17 + +define i1 @and_slt_sle_swap(i8 %x) { +; CHECK-LABEL: @and_slt_sle_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x <s 17 + +define i1 @and_slt_slt_swap(i8 %x) { +; CHECK-LABEL: @and_slt_slt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x >=u 17 + +define i1 @and_slt_uge_swap(i8 %x) { +; CHECK-LABEL: @and_slt_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x >u 17 + +define i1 @and_slt_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_slt_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x <=u 17 + +define i1 @and_slt_ule_swap(i8 %x) { +; CHECK-LABEL: @and_slt_ule_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <s 23 && x <u 17 + +define i1 @and_slt_ult_swap(i8 %x) { +; CHECK-LABEL: @and_slt_ult_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; uge +; x >=u 23 && x == 17 + +define i1 @and_uge_eq_swap(i8 %x) { +; CHECK-LABEL: @and_uge_eq_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp uge i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x != 17 + +define i1 @and_uge_ne_swap(i8 %x) { +; CHECK-LABEL: @and_uge_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x >=s 17 + +define i1 @and_uge_sge_swap(i8 %x) { +; CHECK-LABEL: @and_uge_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x >s 17 + +define i1 @and_uge_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_uge_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x <=s 17 + +define i1 @and_uge_sle_swap(i8 %x) { +; CHECK-LABEL: @and_uge_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x <s 17 + +define i1 @and_uge_slt_swap(i8 %x) { +; CHECK-LABEL: @and_uge_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x >=u 17 + +define i1 @and_uge_uge_swap(i8 %x) { +; CHECK-LABEL: @and_uge_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x >u 17 + +define i1 @and_uge_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_uge_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x <=u 17 + +define i1 @and_uge_ule_swap(i8 %x) { +; CHECK-LABEL: @and_uge_ule_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp uge i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >=u 23 && x <u 17 + +define i1 @and_uge_ult_swap(i8 %x) { +; CHECK-LABEL: @and_uge_ult_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp uge i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ugt +; x >u 23 && x == 17 + +define i1 @and_ugt_eq_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_eq_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp ugt i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x != 17 + +define i1 @and_ugt_ne_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x >=s 17 + +define i1 @and_ugt_sge_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x >s 17 + +define i1 @and_ugt_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x <=s 17 + +define i1 @and_ugt_sle_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x <s 17 + +define i1 @and_ugt_slt_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x >=u 17 + +define i1 @and_ugt_uge_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x >u 17 + +define i1 @and_ugt_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x <=u 17 + +define i1 @and_ugt_ule_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_ule_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp ugt i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x >u 23 && x <u 17 + +define i1 @and_ugt_ult_swap(i8 %x) { +; CHECK-LABEL: @and_ugt_ult_swap( +; CHECK-NEXT: ret i1 false +; + %a = icmp ugt i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ule +; x <=u 23 && x == 17 + +define i1 @and_ule_eq_swap(i8 %x) { +; CHECK-LABEL: @and_ule_eq_swap( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x != 17 + +define i1 @and_ule_ne_swap(i8 %x) { +; CHECK-LABEL: @and_ule_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x >=s 17 + +define i1 @and_ule_sge_swap(i8 %x) { +; CHECK-LABEL: @and_ule_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x >s 17 + +define i1 @and_ule_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_ule_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x <=s 17 + +define i1 @and_ule_sle_swap(i8 %x) { +; CHECK-LABEL: @and_ule_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x <s 17 + +define i1 @and_ule_slt_swap(i8 %x) { +; CHECK-LABEL: @and_ule_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x >=u 17 + +define i1 @and_ule_uge_swap(i8 %x) { +; CHECK-LABEL: @and_ule_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x >u 17 + +define i1 @and_ule_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_ule_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x <=u 17 + +define i1 @and_ule_ule_swap(i8 %x) { +; CHECK-LABEL: @and_ule_ule_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <=u 23 && x <u 17 + +define i1 @and_ule_ult_swap(i8 %x) { +; CHECK-LABEL: @and_ule_ult_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; ult +; x <u 23 && x == 17 + +define i1 @and_ult_eq_swap(i8 %x) { +; CHECK-LABEL: @and_ult_eq_swap( +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x != 17 + +define i1 @and_ult_ne_swap(i8 %x) { +; CHECK-LABEL: @and_ult_ne_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x >=s 17 + +define i1 @and_ult_sge_swap(i8 %x) { +; CHECK-LABEL: @and_ult_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x >s 17 + +define i1 @and_ult_sgt_swap(i8 %x) { +; CHECK-LABEL: @and_ult_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x <=s 17 + +define i1 @and_ult_sle_swap(i8 %x) { +; CHECK-LABEL: @and_ult_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x <s 17 + +define i1 @and_ult_slt_swap(i8 %x) { +; CHECK-LABEL: @and_ult_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x >=u 17 + +define i1 @and_ult_uge_swap(i8 %x) { +; CHECK-LABEL: @and_ult_uge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x >u 17 + +define i1 @and_ult_ugt_swap(i8 %x) { +; CHECK-LABEL: @and_ult_ugt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x <=u 17 + +define i1 @and_ult_ule_swap(i8 %x) { +; CHECK-LABEL: @and_ult_ule_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; x <u 23 && x <u 17 + +define i1 @and_ult_ult_swap(i8 %x) { +; CHECK-LABEL: @and_ult_ult_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = and i1 %a, %b + ret i1 %c +} + +; eq +; x == 13 || x == 17 + +define i1 @or_eq_eq(i8 %x) { +; CHECK-LABEL: @or_eq_eq( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x != 17 + +define i1 @or_eq_ne(i8 %x) { +; CHECK-LABEL: @or_eq_ne( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x >=s 17 + +define i1 @or_eq_sge(i8 %x) { +; CHECK-LABEL: @or_eq_sge( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x >s 17 + +define i1 @or_eq_sgt(i8 %x) { +; CHECK-LABEL: @or_eq_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x <=s 17 + +define i1 @or_eq_sle(i8 %x) { +; CHECK-LABEL: @or_eq_sle( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x <s 17 + +define i1 @or_eq_slt(i8 %x) { +; CHECK-LABEL: @or_eq_slt( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x >=u 17 + +define i1 @or_eq_uge(i8 %x) { +; CHECK-LABEL: @or_eq_uge( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x >u 17 + +define i1 @or_eq_ugt(i8 %x) { +; CHECK-LABEL: @or_eq_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x <=u 17 + +define i1 @or_eq_ule(i8 %x) { +; CHECK-LABEL: @or_eq_ule( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 13 || x <u 17 + +define i1 @or_eq_ult(i8 %x) { +; CHECK-LABEL: @or_eq_ult( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ne +; x != 13 || x == 17 + +define i1 @or_ne_eq(i8 %x) { +; CHECK-LABEL: @or_ne_eq( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x != 17 + +define i1 @or_ne_ne(i8 %x) { +; CHECK-LABEL: @or_ne_ne( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x >=s 17 + +define i1 @or_ne_sge(i8 %x) { +; CHECK-LABEL: @or_ne_sge( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x >s 17 + +define i1 @or_ne_sgt(i8 %x) { +; CHECK-LABEL: @or_ne_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x <=s 17 + +define i1 @or_ne_sle(i8 %x) { +; CHECK-LABEL: @or_ne_sle( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x <s 17 + +define i1 @or_ne_slt(i8 %x) { +; CHECK-LABEL: @or_ne_slt( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x >=u 17 + +define i1 @or_ne_uge(i8 %x) { +; CHECK-LABEL: @or_ne_uge( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x >u 17 + +define i1 @or_ne_ugt(i8 %x) { +; CHECK-LABEL: @or_ne_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x <=u 17 + +define i1 @or_ne_ule(i8 %x) { +; CHECK-LABEL: @or_ne_ule( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 13 || x <u 17 + +define i1 @or_ne_ult(i8 %x) { +; CHECK-LABEL: @or_ne_ult( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; sge +; x >=s 13 || x == 17 + +define i1 @or_sge_eq(i8 %x) { +; CHECK-LABEL: @or_sge_eq( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x != 17 + +define i1 @or_sge_ne(i8 %x) { +; CHECK-LABEL: @or_sge_ne( +; CHECK-NEXT: ret i1 true +; + %a = icmp sge i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x >=s 17 + +define i1 @or_sge_sge(i8 %x) { +; CHECK-LABEL: @or_sge_sge( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x >s 17 + +define i1 @or_sge_sgt(i8 %x) { +; CHECK-LABEL: @or_sge_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sge i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x <=s 17 + +define i1 @or_sge_sle(i8 %x) { +; CHECK-LABEL: @or_sge_sle( +; CHECK-NEXT: ret i1 true +; + %a = icmp sge i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x <s 17 + +define i1 @or_sge_slt(i8 %x) { +; CHECK-LABEL: @or_sge_slt( +; CHECK-NEXT: ret i1 true +; + %a = icmp sge i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x >=u 17 + +define i1 @or_sge_uge(i8 %x) { +; CHECK-LABEL: @or_sge_uge( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x >u 17 + +define i1 @or_sge_ugt(i8 %x) { +; CHECK-LABEL: @or_sge_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x <=u 17 + +define i1 @or_sge_ule(i8 %x) { +; CHECK-LABEL: @or_sge_ule( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 13 || x <u 17 + +define i1 @or_sge_ult(i8 %x) { +; CHECK-LABEL: @or_sge_ult( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; sgt +; x >s 13 || x == 17 + +define i1 @or_sgt_eq(i8 %x) { +; CHECK-LABEL: @or_sgt_eq( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x != 17 + +define i1 @or_sgt_ne(i8 %x) { +; CHECK-LABEL: @or_sgt_ne( +; CHECK-NEXT: ret i1 true +; + %a = icmp sgt i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x >=s 17 + +define i1 @or_sgt_sge(i8 %x) { +; CHECK-LABEL: @or_sgt_sge( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x >s 17 + +define i1 @or_sgt_sgt(i8 %x) { +; CHECK-LABEL: @or_sgt_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x <=s 17 + +define i1 @or_sgt_sle(i8 %x) { +; CHECK-LABEL: @or_sgt_sle( +; CHECK-NEXT: ret i1 true +; + %a = icmp sgt i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x <s 17 + +define i1 @or_sgt_slt(i8 %x) { +; CHECK-LABEL: @or_sgt_slt( +; CHECK-NEXT: ret i1 true +; + %a = icmp sgt i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x >=u 17 + +define i1 @or_sgt_uge(i8 %x) { +; CHECK-LABEL: @or_sgt_uge( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x >u 17 + +define i1 @or_sgt_ugt(i8 %x) { +; CHECK-LABEL: @or_sgt_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x <=u 17 + +define i1 @or_sgt_ule(i8 %x) { +; CHECK-LABEL: @or_sgt_ule( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 13 || x <u 17 + +define i1 @or_sgt_ult(i8 %x) { +; CHECK-LABEL: @or_sgt_ult( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; sle +; x <=s 13 || x == 17 + +define i1 @or_sle_eq(i8 %x) { +; CHECK-LABEL: @or_sle_eq( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x != 17 + +define i1 @or_sle_ne(i8 %x) { +; CHECK-LABEL: @or_sle_ne( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x >=s 17 + +define i1 @or_sle_sge(i8 %x) { +; CHECK-LABEL: @or_sle_sge( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x >s 17 + +define i1 @or_sle_sgt(i8 %x) { +; CHECK-LABEL: @or_sle_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x <=s 17 + +define i1 @or_sle_sle(i8 %x) { +; CHECK-LABEL: @or_sle_sle( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x <s 17 + +define i1 @or_sle_slt(i8 %x) { +; CHECK-LABEL: @or_sle_slt( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sle i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x >=u 17 + +define i1 @or_sle_uge(i8 %x) { +; CHECK-LABEL: @or_sle_uge( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x >u 17 + +define i1 @or_sle_ugt(i8 %x) { +; CHECK-LABEL: @or_sle_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x <=u 17 + +define i1 @or_sle_ule(i8 %x) { +; CHECK-LABEL: @or_sle_ule( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 13 || x <u 17 + +define i1 @or_sle_ult(i8 %x) { +; CHECK-LABEL: @or_sle_ult( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sle i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; slt +; x <s 13 || x == 17 + +define i1 @or_slt_eq(i8 %x) { +; CHECK-LABEL: @or_slt_eq( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x != 17 + +define i1 @or_slt_ne(i8 %x) { +; CHECK-LABEL: @or_slt_ne( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x >=s 17 + +define i1 @or_slt_sge(i8 %x) { +; CHECK-LABEL: @or_slt_sge( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x >s 17 + +define i1 @or_slt_sgt(i8 %x) { +; CHECK-LABEL: @or_slt_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x <=s 17 + +define i1 @or_slt_sle(i8 %x) { +; CHECK-LABEL: @or_slt_sle( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x <s 17 + +define i1 @or_slt_slt(i8 %x) { +; CHECK-LABEL: @or_slt_slt( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp slt i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x >=u 17 + +define i1 @or_slt_uge(i8 %x) { +; CHECK-LABEL: @or_slt_uge( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x >u 17 + +define i1 @or_slt_ugt(i8 %x) { +; CHECK-LABEL: @or_slt_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x <=u 17 + +define i1 @or_slt_ule(i8 %x) { +; CHECK-LABEL: @or_slt_ule( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 13 || x <u 17 + +define i1 @or_slt_ult(i8 %x) { +; CHECK-LABEL: @or_slt_ult( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp slt i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; uge +; x >=u 13 || x == 17 + +define i1 @or_uge_eq(i8 %x) { +; CHECK-LABEL: @or_uge_eq( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x != 17 + +define i1 @or_uge_ne(i8 %x) { +; CHECK-LABEL: @or_uge_ne( +; CHECK-NEXT: ret i1 true +; + %a = icmp uge i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x >=s 17 + +define i1 @or_uge_sge(i8 %x) { +; CHECK-LABEL: @or_uge_sge( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x >s 17 + +define i1 @or_uge_sgt(i8 %x) { +; CHECK-LABEL: @or_uge_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x <=s 17 + +define i1 @or_uge_sle(i8 %x) { +; CHECK-LABEL: @or_uge_sle( +; CHECK-NEXT: ret i1 true +; + %a = icmp uge i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x <s 17 + +define i1 @or_uge_slt(i8 %x) { +; CHECK-LABEL: @or_uge_slt( +; CHECK-NEXT: ret i1 true +; + %a = icmp uge i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x >=u 17 + +define i1 @or_uge_uge(i8 %x) { +; CHECK-LABEL: @or_uge_uge( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x >u 17 + +define i1 @or_uge_ugt(i8 %x) { +; CHECK-LABEL: @or_uge_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp uge i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x <=u 17 + +define i1 @or_uge_ule(i8 %x) { +; CHECK-LABEL: @or_uge_ule( +; CHECK-NEXT: ret i1 true +; + %a = icmp uge i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 13 || x <u 17 + +define i1 @or_uge_ult(i8 %x) { +; CHECK-LABEL: @or_uge_ult( +; CHECK-NEXT: ret i1 true +; + %a = icmp uge i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ugt +; x >u 13 || x == 17 + +define i1 @or_ugt_eq(i8 %x) { +; CHECK-LABEL: @or_ugt_eq( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x != 17 + +define i1 @or_ugt_ne(i8 %x) { +; CHECK-LABEL: @or_ugt_ne( +; CHECK-NEXT: ret i1 true +; + %a = icmp ugt i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x >=s 17 + +define i1 @or_ugt_sge(i8 %x) { +; CHECK-LABEL: @or_ugt_sge( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x >s 17 + +define i1 @or_ugt_sgt(i8 %x) { +; CHECK-LABEL: @or_ugt_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x <=s 17 + +define i1 @or_ugt_sle(i8 %x) { +; CHECK-LABEL: @or_ugt_sle( +; CHECK-NEXT: ret i1 true +; + %a = icmp ugt i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x <s 17 + +define i1 @or_ugt_slt(i8 %x) { +; CHECK-LABEL: @or_ugt_slt( +; CHECK-NEXT: ret i1 true +; + %a = icmp ugt i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x >=u 17 + +define i1 @or_ugt_uge(i8 %x) { +; CHECK-LABEL: @or_ugt_uge( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x >u 17 + +define i1 @or_ugt_ugt(i8 %x) { +; CHECK-LABEL: @or_ugt_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 13 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ugt i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x <=u 17 + +define i1 @or_ugt_ule(i8 %x) { +; CHECK-LABEL: @or_ugt_ule( +; CHECK-NEXT: ret i1 true +; + %a = icmp ugt i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 13 || x <u 17 + +define i1 @or_ugt_ult(i8 %x) { +; CHECK-LABEL: @or_ugt_ult( +; CHECK-NEXT: ret i1 true +; + %a = icmp ugt i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ule +; x <=u 13 || x == 17 + +define i1 @or_ule_eq(i8 %x) { +; CHECK-LABEL: @or_ule_eq( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x != 17 + +define i1 @or_ule_ne(i8 %x) { +; CHECK-LABEL: @or_ule_ne( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x >=s 17 + +define i1 @or_ule_sge(i8 %x) { +; CHECK-LABEL: @or_ule_sge( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x >s 17 + +define i1 @or_ule_sgt(i8 %x) { +; CHECK-LABEL: @or_ule_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x <=s 17 + +define i1 @or_ule_sle(i8 %x) { +; CHECK-LABEL: @or_ule_sle( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x <s 17 + +define i1 @or_ule_slt(i8 %x) { +; CHECK-LABEL: @or_ule_slt( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x >=u 17 + +define i1 @or_ule_uge(i8 %x) { +; CHECK-LABEL: @or_ule_uge( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x >u 17 + +define i1 @or_ule_ugt(i8 %x) { +; CHECK-LABEL: @or_ule_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x <=u 17 + +define i1 @or_ule_ule(i8 %x) { +; CHECK-LABEL: @or_ule_ule( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 13 || x <u 17 + +define i1 @or_ule_ult(i8 %x) { +; CHECK-LABEL: @or_ule_ult( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ule i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ult +; x <u 13 || x == 17 + +define i1 @or_ult_eq(i8 %x) { +; CHECK-LABEL: @or_ult_eq( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 13 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x != 17 + +define i1 @or_ult_ne(i8 %x) { +; CHECK-LABEL: @or_ult_ne( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 13 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x >=s 17 + +define i1 @or_ult_sge(i8 %x) { +; CHECK-LABEL: @or_ult_sge( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 13 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x >s 17 + +define i1 @or_ult_sgt(i8 %x) { +; CHECK-LABEL: @or_ult_sgt( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 13 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x <=s 17 + +define i1 @or_ult_sle(i8 %x) { +; CHECK-LABEL: @or_ult_sle( +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 13 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x <s 17 + +define i1 @or_ult_slt(i8 %x) { +; CHECK-LABEL: @or_ult_slt( +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 13 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x >=u 17 + +define i1 @or_ult_uge(i8 %x) { +; CHECK-LABEL: @or_ult_uge( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 13 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x >u 17 + +define i1 @or_ult_ugt(i8 %x) { +; CHECK-LABEL: @or_ult_ugt( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 13 +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 13 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x <=u 17 + +define i1 @or_ult_ule(i8 %x) { +; CHECK-LABEL: @or_ult_ule( +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 13 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 13 || x <u 17 + +define i1 @or_ult_ult(i8 %x) { +; CHECK-LABEL: @or_ult_ult( +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ult i8 %x, 13 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; eq +; x == 23 || x == 17 + +define i1 @or_eq_eq_swap(i8 %x) { +; CHECK-LABEL: @or_eq_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x != 17 + +define i1 @or_eq_ne_swap(i8 %x) { +; CHECK-LABEL: @or_eq_ne_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x >=s 17 + +define i1 @or_eq_sge_swap(i8 %x) { +; CHECK-LABEL: @or_eq_sge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x >s 17 + +define i1 @or_eq_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_eq_sgt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x <=s 17 + +define i1 @or_eq_sle_swap(i8 %x) { +; CHECK-LABEL: @or_eq_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x <s 17 + +define i1 @or_eq_slt_swap(i8 %x) { +; CHECK-LABEL: @or_eq_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x >=u 17 + +define i1 @or_eq_uge_swap(i8 %x) { +; CHECK-LABEL: @or_eq_uge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x >u 17 + +define i1 @or_eq_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_eq_ugt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp eq i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x <=u 17 + +define i1 @or_eq_ule_swap(i8 %x) { +; CHECK-LABEL: @or_eq_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x == 23 || x <u 17 + +define i1 @or_eq_ult_swap(i8 %x) { +; CHECK-LABEL: @or_eq_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp eq i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp eq i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ne +; x != 23 || x == 17 + +define i1 @or_ne_eq_swap(i8 %x) { +; CHECK-LABEL: @or_ne_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x != 17 + +define i1 @or_ne_ne_swap(i8 %x) { +; CHECK-LABEL: @or_ne_ne_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x >=s 17 + +define i1 @or_ne_sge_swap(i8 %x) { +; CHECK-LABEL: @or_ne_sge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x >s 17 + +define i1 @or_ne_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_ne_sgt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x <=s 17 + +define i1 @or_ne_sle_swap(i8 %x) { +; CHECK-LABEL: @or_ne_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x <s 17 + +define i1 @or_ne_slt_swap(i8 %x) { +; CHECK-LABEL: @or_ne_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x >=u 17 + +define i1 @or_ne_uge_swap(i8 %x) { +; CHECK-LABEL: @or_ne_uge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x >u 17 + +define i1 @or_ne_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_ne_ugt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ne i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x <=u 17 + +define i1 @or_ne_ule_swap(i8 %x) { +; CHECK-LABEL: @or_ne_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x != 23 || x <u 17 + +define i1 @or_ne_ult_swap(i8 %x) { +; CHECK-LABEL: @or_ne_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ne i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ne i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; sge +; x >=s 23 || x == 17 + +define i1 @or_sge_eq_swap(i8 %x) { +; CHECK-LABEL: @or_sge_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x != 17 + +define i1 @or_sge_ne_swap(i8 %x) { +; CHECK-LABEL: @or_sge_ne_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x >=s 17 + +define i1 @or_sge_sge_swap(i8 %x) { +; CHECK-LABEL: @or_sge_sge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x >s 17 + +define i1 @or_sge_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_sge_sgt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x <=s 17 + +define i1 @or_sge_sle_swap(i8 %x) { +; CHECK-LABEL: @or_sge_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x <s 17 + +define i1 @or_sge_slt_swap(i8 %x) { +; CHECK-LABEL: @or_sge_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x >=u 17 + +define i1 @or_sge_uge_swap(i8 %x) { +; CHECK-LABEL: @or_sge_uge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x >u 17 + +define i1 @or_sge_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_sge_ugt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sge i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x <=u 17 + +define i1 @or_sge_ule_swap(i8 %x) { +; CHECK-LABEL: @or_sge_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=s 23 || x <u 17 + +define i1 @or_sge_ult_swap(i8 %x) { +; CHECK-LABEL: @or_sge_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sge i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; sgt +; x >s 23 || x == 17 + +define i1 @or_sgt_eq_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x != 17 + +define i1 @or_sgt_ne_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_ne_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x >=s 17 + +define i1 @or_sgt_sge_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_sge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x >s 17 + +define i1 @or_sgt_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_sgt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x <=s 17 + +define i1 @or_sgt_sle_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x <s 17 + +define i1 @or_sgt_slt_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x >=u 17 + +define i1 @or_sgt_uge_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_uge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x >u 17 + +define i1 @or_sgt_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_ugt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x <=u 17 + +define i1 @or_sgt_ule_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >s 23 || x <u 17 + +define i1 @or_sgt_ult_swap(i8 %x) { +; CHECK-LABEL: @or_sgt_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp sgt i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; sle +; x <=s 23 || x == 17 + +define i1 @or_sle_eq_swap(i8 %x) { +; CHECK-LABEL: @or_sle_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x != 17 + +define i1 @or_sle_ne_swap(i8 %x) { +; CHECK-LABEL: @or_sle_ne_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp sle i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x >=s 17 + +define i1 @or_sle_sge_swap(i8 %x) { +; CHECK-LABEL: @or_sle_sge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp sle i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x >s 17 + +define i1 @or_sle_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_sle_sgt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp sle i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x <=s 17 + +define i1 @or_sle_sle_swap(i8 %x) { +; CHECK-LABEL: @or_sle_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x <s 17 + +define i1 @or_sle_slt_swap(i8 %x) { +; CHECK-LABEL: @or_sle_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x >=u 17 + +define i1 @or_sle_uge_swap(i8 %x) { +; CHECK-LABEL: @or_sle_uge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp sle i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x >u 17 + +define i1 @or_sle_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_sle_ugt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp sle i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x <=u 17 + +define i1 @or_sle_ule_swap(i8 %x) { +; CHECK-LABEL: @or_sle_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=s 23 || x <u 17 + +define i1 @or_sle_ult_swap(i8 %x) { +; CHECK-LABEL: @or_sle_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp sle i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp sle i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; slt +; x <s 23 || x == 17 + +define i1 @or_slt_eq_swap(i8 %x) { +; CHECK-LABEL: @or_slt_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x != 17 + +define i1 @or_slt_ne_swap(i8 %x) { +; CHECK-LABEL: @or_slt_ne_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp slt i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x >=s 17 + +define i1 @or_slt_sge_swap(i8 %x) { +; CHECK-LABEL: @or_slt_sge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp slt i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x >s 17 + +define i1 @or_slt_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_slt_sgt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp slt i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x <=s 17 + +define i1 @or_slt_sle_swap(i8 %x) { +; CHECK-LABEL: @or_slt_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x <s 17 + +define i1 @or_slt_slt_swap(i8 %x) { +; CHECK-LABEL: @or_slt_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x >=u 17 + +define i1 @or_slt_uge_swap(i8 %x) { +; CHECK-LABEL: @or_slt_uge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp slt i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x >u 17 + +define i1 @or_slt_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_slt_ugt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp slt i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x <=u 17 + +define i1 @or_slt_ule_swap(i8 %x) { +; CHECK-LABEL: @or_slt_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <s 23 || x <u 17 + +define i1 @or_slt_ult_swap(i8 %x) { +; CHECK-LABEL: @or_slt_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp slt i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp slt i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; uge +; x >=u 23 || x == 17 + +define i1 @or_uge_eq_swap(i8 %x) { +; CHECK-LABEL: @or_uge_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x != 17 + +define i1 @or_uge_ne_swap(i8 %x) { +; CHECK-LABEL: @or_uge_ne_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x >=s 17 + +define i1 @or_uge_sge_swap(i8 %x) { +; CHECK-LABEL: @or_uge_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x >s 17 + +define i1 @or_uge_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_uge_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x <=s 17 + +define i1 @or_uge_sle_swap(i8 %x) { +; CHECK-LABEL: @or_uge_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x <s 17 + +define i1 @or_uge_slt_swap(i8 %x) { +; CHECK-LABEL: @or_uge_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x >=u 17 + +define i1 @or_uge_uge_swap(i8 %x) { +; CHECK-LABEL: @or_uge_uge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x >u 17 + +define i1 @or_uge_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_uge_ugt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp uge i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x <=u 17 + +define i1 @or_uge_ule_swap(i8 %x) { +; CHECK-LABEL: @or_uge_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >=u 23 || x <u 17 + +define i1 @or_uge_ult_swap(i8 %x) { +; CHECK-LABEL: @or_uge_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp uge i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp uge i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ugt +; x >u 23 || x == 17 + +define i1 @or_ugt_eq_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp eq i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x != 17 + +define i1 @or_ugt_ne_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_ne_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ne i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x >=s 17 + +define i1 @or_ugt_sge_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x >s 17 + +define i1 @or_ugt_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x <=s 17 + +define i1 @or_ugt_sle_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x <s 17 + +define i1 @or_ugt_slt_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x >=u 17 + +define i1 @or_ugt_uge_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_uge_swap( +; CHECK-NEXT: [[B:%.*]] = icmp uge i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x >u 17 + +define i1 @or_ugt_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_ugt_swap( +; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 %x, 17 +; CHECK-NEXT: ret i1 [[B]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x <=u 17 + +define i1 @or_ugt_ule_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ule i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x >u 23 || x <u 17 + +define i1 @or_ugt_ult_swap(i8 %x) { +; CHECK-LABEL: @or_ugt_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp ult i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ugt i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ule +; x <=u 23 || x == 17 + +define i1 @or_ule_eq_swap(i8 %x) { +; CHECK-LABEL: @or_ule_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x != 17 + +define i1 @or_ule_ne_swap(i8 %x) { +; CHECK-LABEL: @or_ule_ne_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ule i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x >=s 17 + +define i1 @or_ule_sge_swap(i8 %x) { +; CHECK-LABEL: @or_ule_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x >s 17 + +define i1 @or_ule_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_ule_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x <=s 17 + +define i1 @or_ule_sle_swap(i8 %x) { +; CHECK-LABEL: @or_ule_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x <s 17 + +define i1 @or_ule_slt_swap(i8 %x) { +; CHECK-LABEL: @or_ule_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ule i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x >=u 17 + +define i1 @or_ule_uge_swap(i8 %x) { +; CHECK-LABEL: @or_ule_uge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ule i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x >u 17 + +define i1 @or_ule_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_ule_ugt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ule i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x <=u 17 + +define i1 @or_ule_ule_swap(i8 %x) { +; CHECK-LABEL: @or_ule_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <=u 23 || x <u 17 + +define i1 @or_ule_ult_swap(i8 %x) { +; CHECK-LABEL: @or_ule_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ule i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ule i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; ult +; x <u 23 || x == 17 + +define i1 @or_ult_eq_swap(i8 %x) { +; CHECK-LABEL: @or_ult_eq_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 23 + %b = icmp eq i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x != 17 + +define i1 @or_ult_ne_swap(i8 %x) { +; CHECK-LABEL: @or_ult_ne_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ult i8 %x, 23 + %b = icmp ne i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x >=s 17 + +define i1 @or_ult_sge_swap(i8 %x) { +; CHECK-LABEL: @or_ult_sge_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sge i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp sge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x >s 17 + +define i1 @or_ult_sgt_swap(i8 %x) { +; CHECK-LABEL: @or_ult_sgt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sgt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp sgt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x <=s 17 + +define i1 @or_ult_sle_swap(i8 %x) { +; CHECK-LABEL: @or_ult_sle_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp sle i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp sle i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x <s 17 + +define i1 @or_ult_slt_swap(i8 %x) { +; CHECK-LABEL: @or_ult_slt_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: [[B:%.*]] = icmp slt i8 %x, 17 +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: ret i1 [[C]] +; + %a = icmp ult i8 %x, 23 + %b = icmp slt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x >=u 17 + +define i1 @or_ult_uge_swap(i8 %x) { +; CHECK-LABEL: @or_ult_uge_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ult i8 %x, 23 + %b = icmp uge i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x >u 17 + +define i1 @or_ult_ugt_swap(i8 %x) { +; CHECK-LABEL: @or_ult_ugt_swap( +; CHECK-NEXT: ret i1 true +; + %a = icmp ult i8 %x, 23 + %b = icmp ugt i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x <=u 17 + +define i1 @or_ult_ule_swap(i8 %x) { +; CHECK-LABEL: @or_ult_ule_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 23 + %b = icmp ule i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; x <u 23 || x <u 17 + +define i1 @or_ult_ult_swap(i8 %x) { +; CHECK-LABEL: @or_ult_ult_swap( +; CHECK-NEXT: [[A:%.*]] = icmp ult i8 %x, 23 +; CHECK-NEXT: ret i1 [[A]] +; + %a = icmp ult i8 %x, 23 + %b = icmp ult i8 %x, 17 + %c = or i1 %a, %b + ret i1 %c +} + +; Special case - slt is uge +; x <u 31 && x <s 0 + +define i1 @empty2(i32 %x) { +; CHECK-LABEL: @empty2( +; CHECK-NEXT: ret i1 false +; + %a = icmp ult i32 %x, 31 + %b = icmp slt i32 %x, 0 + %c = and i1 %a, %b + ret i1 %c +} + diff --git a/llvm/test/Transforms/InstSimplify/implies.ll b/llvm/test/Transforms/InstSimplify/implies.ll new file mode 100644 index 00000000000..56e1e6a29c4 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/implies.ll @@ -0,0 +1,257 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt -S %s -instsimplify | FileCheck %s + +; A ==> A -> true +define i1 @test(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test( +; CHECK: ret i1 true +; + %var29 = icmp slt i32 %i, %length.i + %res = icmp uge i1 %var29, %var29 + ret i1 %res +} + +; i +_{nsw} C_{>0} <s L ==> i <s L -> true +define i1 @test2(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test2( +; CHECK: ret i1 true +; + %iplus1 = add nsw i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; i + C_{>0} <s L ==> i <s L -> unknown without the nsw +define i1 @test2_neg(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test2_neg( +; CHECK: [[IPLUS1:%.*]] = add i32 %i, 1 +; CHECK-NEXT: [[VAR29:%.*]] = icmp slt i32 %i, %length.i +; CHECK-NEXT: [[VAR30:%.*]] = icmp slt i32 [[IPLUS1]], %length.i +; CHECK-NEXT: [[RES:%.*]] = icmp ule i1 [[VAR30]], [[VAR29]] +; CHECK-NEXT: ret i1 [[RES]] +; + %iplus1 = add i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; sle is not implication +define i1 @test2_neg2(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test2_neg2( +; CHECK: [[IPLUS1:%.*]] = add i32 %i, 1 +; CHECK-NEXT: [[VAR29:%.*]] = icmp slt i32 %i, %length.i +; CHECK-NEXT: [[VAR30:%.*]] = icmp slt i32 [[IPLUS1]], %length.i +; CHECK-NEXT: [[RES:%.*]] = icmp sle i1 [[VAR30]], [[VAR29]] +; CHECK-NEXT: ret i1 [[RES]] +; + %iplus1 = add i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp sle i1 %var30, %var29 + ret i1 %res +} + +; The binary operator has to be an add +define i1 @test2_neg3(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test2_neg3( +; CHECK: [[IPLUS1:%.*]] = sub nsw i32 %i, 1 +; CHECK-NEXT: [[VAR29:%.*]] = icmp slt i32 %i, %length.i +; CHECK-NEXT: [[VAR30:%.*]] = icmp slt i32 [[IPLUS1]], %length.i +; CHECK-NEXT: [[RES:%.*]] = icmp ule i1 [[VAR30]], [[VAR29]] +; CHECK-NEXT: ret i1 [[RES]] +; + %iplus1 = sub nsw i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; i +_{nsw} C_{>0} <s L ==> i <s L -> true +; With an inverted conditional (ule B A rather than canonical ugt A B +define i1 @test3(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test3( +; CHECK: ret i1 true +; + %iplus1 = add nsw i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp uge i1 %var29, %var30 + ret i1 %res +} + +; i +_{nuw} C <u L ==> i <u L +define i1 @test4(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test4( +; CHECK: ret i1 true +; + %iplus1 = add nuw i32 %i, 1 + %var29 = icmp ult i32 %i, %length.i + %var30 = icmp ult i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; A ==> A for vectors +define <4 x i1> @test5(<4 x i1> %vec) { +; CHECK-LABEL: @test5( +; CHECK: ret <4 x i1> <i1 true, i1 true, i1 true, i1 true> +; + %res = icmp ule <4 x i1> %vec, %vec + ret <4 x i1> %res +} + +; Don't crash on vector inputs - pr25040 +define <4 x i1> @test6(<4 x i1> %a, <4 x i1> %b) { +; CHECK-LABEL: @test6( +; CHECK: [[RES:%.*]] = icmp ule <4 x i1> %a, %b +; CHECK-NEXT: ret <4 x i1> [[RES]] +; + %res = icmp ule <4 x i1> %a, %b + ret <4 x i1> %res +} + +; i +_{nsw} 1 <s L ==> i < L +_{nsw} 1 +define i1 @test7(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test7( +; CHECK: ret i1 true +; + %iplus1 = add nsw i32 %i, 1 + %len.plus.one = add nsw i32 %length.i, 1 + %var29 = icmp slt i32 %i, %len.plus.one + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; i +_{nuw} 1 <u L ==> i < L +_{nuw} 1 +define i1 @test8(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test8( +; CHECK: ret i1 true +; + %iplus1 = add nuw i32 %i, 1 + %len.plus.one = add nuw i32 %length.i, 1 + %var29 = icmp ult i32 %i, %len.plus.one + %var30 = icmp ult i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; i +_{nuw} C <u L ==> i < L, even if C is negative +define i1 @test9(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test9( +; CHECK: ret i1 true +; + %iplus1 = add nuw i32 %i, -100 + %var29 = icmp ult i32 %i, %length.i + %var30 = icmp ult i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +define i1 @test10(i32 %length.i, i32 %x.full) { +; CHECK-LABEL: @test10( +; CHECK: ret i1 true +; + %x = and i32 %x.full, 4294901760 ;; 4294901760 == 0xffff0000 + %large = or i32 %x, 100 + %small = or i32 %x, 90 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +define i1 @test11(i32 %length.i, i32 %x) { +; CHECK-LABEL: @test11( +; CHECK: [[LARGE:%.*]] = or i32 %x, 100 +; CHECK-NEXT: [[SMALL:%.*]] = or i32 %x, 90 +; CHECK-NEXT: [[KNOWN:%.*]] = icmp ult i32 [[LARGE]], %length.i +; CHECK-NEXT: [[TO_PROVE:%.*]] = icmp ult i32 [[SMALL]], %length.i +; CHECK-NEXT: [[RES:%.*]] = icmp ule i1 [[KNOWN]], [[TO_PROVE]] +; CHECK-NEXT: ret i1 [[RES]] +; + %large = or i32 %x, 100 + %small = or i32 %x, 90 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +define i1 @test12(i32 %length.i, i32 %x.full) { +; CHECK-LABEL: @test12( +; CHECK: [[X:%.*]] = and i32 [[X:%.*]].full, -65536 +; CHECK-NEXT: [[LARGE:%.*]] = or i32 [[X]], 65536 +; CHECK-NEXT: [[SMALL:%.*]] = or i32 [[X]], 90 +; CHECK-NEXT: [[KNOWN:%.*]] = icmp ult i32 [[LARGE]], %length.i +; CHECK-NEXT: [[TO_PROVE:%.*]] = icmp ult i32 [[SMALL]], %length.i +; CHECK-NEXT: [[RES:%.*]] = icmp ule i1 [[KNOWN]], [[TO_PROVE]] +; CHECK-NEXT: ret i1 [[RES]] +; + %x = and i32 %x.full, 4294901760 ;; 4294901760 == 0xffff0000 + %large = or i32 %x, 65536 ;; 65536 == 0x00010000 + %small = or i32 %x, 90 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +define i1 @test13(i32 %length.i, i32 %x) { +; CHECK-LABEL: @test13( +; CHECK: ret i1 true +; + %large = add nuw i32 %x, 100 + %small = add nuw i32 %x, 90 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +define i1 @test14(i32 %length.i, i32 %x.full) { +; CHECK-LABEL: @test14( +; CHECK: ret i1 true +; + %x = and i32 %x.full, 4294905615 ;; 4294905615 == 0xffff0f0f + %large = or i32 %x, 8224 ;; == 0x2020 + %small = or i32 %x, 4112 ;; == 0x1010 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +define i1 @test15(i32 %length.i, i32 %x) { +; CHECK-LABEL: @test15( +; CHECK: [[LARGE:%.*]] = add nuw i32 %x, 100 +; CHECK-NEXT: [[SMALL:%.*]] = add nuw i32 %x, 110 +; CHECK-NEXT: [[KNOWN:%.*]] = icmp ult i32 [[LARGE]], %length.i +; CHECK-NEXT: [[TO_PROVE:%.*]] = icmp ult i32 [[SMALL]], %length.i +; CHECK-NEXT: [[RES:%.*]] = icmp ule i1 [[KNOWN]], [[TO_PROVE]] +; CHECK-NEXT: ret i1 [[RES]] +; + %large = add nuw i32 %x, 100 + %small = add nuw i32 %x, 110 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +; X >=(s) Y == X ==> Y (i1 1 becomes -1 for reasoning) +define i1 @test_sge(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test_sge( +; CHECK: ret i1 true +; + %iplus1 = add nsw nuw i32 %i, 1 + %var29 = icmp ult i32 %i, %length.i + %var30 = icmp ult i32 %iplus1, %length.i + %res = icmp sge i1 %var30, %var29 + ret i1 %res +} diff --git a/llvm/test/Transforms/InstSimplify/insertelement.ll b/llvm/test/Transforms/InstSimplify/insertelement.ll new file mode 100644 index 00000000000..3524f2145ac --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/insertelement.ll @@ -0,0 +1,31 @@ +; RUN: opt -S -instsimplify < %s | FileCheck %s + +define <4 x i32> @test1(<4 x i32> %A) { + %I = insertelement <4 x i32> %A, i32 5, i64 4294967296 + ; CHECK: ret <4 x i32> undef + ret <4 x i32> %I +} + +define <4 x i32> @test2(<4 x i32> %A) { + %I = insertelement <4 x i32> %A, i32 5, i64 4 + ; CHECK: ret <4 x i32> undef + ret <4 x i32> %I +} + +define <4 x i32> @test3(<4 x i32> %A) { + %I = insertelement <4 x i32> %A, i32 5, i64 1 + ; CHECK: ret <4 x i32> %I + ret <4 x i32> %I +} + +define <4 x i32> @test4(<4 x i32> %A) { + %I = insertelement <4 x i32> %A, i32 5, i128 100 + ; CHECK: ret <4 x i32> undef + ret <4 x i32> %I +} + +define <4 x i32> @test5(<4 x i32> %A) { + %I = insertelement <4 x i32> %A, i32 5, i64 undef + ; CHECK: ret <4 x i32> undef + ret <4 x i32> %I +} diff --git a/llvm/test/Transforms/InstSimplify/known-never-nan.ll b/llvm/test/Transforms/InstSimplify/known-never-nan.ll new file mode 100644 index 00000000000..d7c2fdc1cb1 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/known-never-nan.ll @@ -0,0 +1,372 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -S -instsimplify | FileCheck %s + +declare double @func() + +define i1 @nnan_call() { +; CHECK-LABEL: @nnan_call( +; CHECK-NEXT: [[OP:%.*]] = call nnan double @func() +; CHECK-NEXT: ret i1 true +; + %op = call nnan double @func() + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @nnan_fabs_src(double %arg) { +; CHECK-LABEL: @nnan_fabs_src( +; CHECK-NEXT: ret i1 false +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.fabs.f64(double %nnan) + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @nnan_canonicalize_src(double %arg) { +; CHECK-LABEL: @nnan_canonicalize_src( +; CHECK-NEXT: ret i1 true +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.canonicalize.f64(double %nnan) + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @nnan_copysign_src(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_copysign_src( +; CHECK-NEXT: ret i1 false +; + %nnan = fadd nnan double %arg0, 1.0 + %op = call double @llvm.copysign.f64(double %nnan, double %arg1) + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @fabs_sqrt_src(double %arg0, double %arg1) { +; CHECK-LABEL: @fabs_sqrt_src( +; CHECK-NEXT: ret i1 true +; + %nnan = fadd nnan double %arg0, 1.0 + %fabs = call double @llvm.fabs.f64(double %nnan) + %op = call double @llvm.sqrt.f64(double %fabs) + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @fabs_sqrt_src_maybe_nan(double %arg0, double %arg1) { +; CHECK-LABEL: @fabs_sqrt_src_maybe_nan( +; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[ARG0:%.*]]) +; CHECK-NEXT: [[OP:%.*]] = call double @llvm.sqrt.f64(double [[FABS]]) +; CHECK-NEXT: [[TMP:%.*]] = fcmp uno double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %fabs = call double @llvm.fabs.f64(double %arg0) + %op = call double @llvm.sqrt.f64(double %fabs) + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @exp_nnan_src(double %arg) { +; CHECK-LABEL: @exp_nnan_src( +; CHECK-NEXT: ret i1 true +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.exp.f64(double %nnan) + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @exp2_nnan_src(double %arg) { +; CHECK-LABEL: @exp2_nnan_src( +; CHECK-NEXT: ret i1 false +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.exp2.f64(double %nnan) + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @floor_nnan_src(double %arg) { +; CHECK-LABEL: @floor_nnan_src( +; CHECK-NEXT: ret i1 true +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.floor.f64(double %nnan) + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @ceil_nnan_src(double %arg) { +; CHECK-LABEL: @ceil_nnan_src( +; CHECK-NEXT: ret i1 false +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.ceil.f64(double %nnan) + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @trunc_nnan_src(double %arg) { +; CHECK-LABEL: @trunc_nnan_src( +; CHECK-NEXT: ret i1 true +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.trunc.f64(double %nnan) + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @rint_nnan_src(double %arg) { +; CHECK-LABEL: @rint_nnan_src( +; CHECK-NEXT: ret i1 false +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.rint.f64(double %nnan) + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @nearbyint_nnan_src(double %arg) { +; CHECK-LABEL: @nearbyint_nnan_src( +; CHECK-NEXT: ret i1 true +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.nearbyint.f64(double %nnan) + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @round_nnan_src(double %arg) { +; CHECK-LABEL: @round_nnan_src( +; CHECK-NEXT: ret i1 false +; + %nnan = fadd nnan double %arg, 1.0 + %op = call double @llvm.round.f64(double %nnan) + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @known_nan_select(i1 %cond, double %arg0, double %arg1) { +; CHECK-LABEL: @known_nan_select( +; CHECK-NEXT: ret i1 true +; + %lhs = fadd nnan double %arg0, 1.0 + %rhs = fadd nnan double %arg1, 2.0 + %op = select i1 %cond, double %lhs, double %rhs + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @select_maybe_nan_lhs(i1 %cond, double %lhs, double %arg1) { +; CHECK-LABEL: @select_maybe_nan_lhs( +; CHECK-NEXT: [[RHS:%.*]] = fadd nnan double [[ARG1:%.*]], 1.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], double [[LHS:%.*]], double [[RHS]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp uno double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %rhs = fadd nnan double %arg1, 1.0 + %op = select i1 %cond, double %lhs, double %rhs + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @select_maybe_nan_rhs(i1 %cond, double %arg0, double %rhs) { +; CHECK-LABEL: @select_maybe_nan_rhs( +; CHECK-NEXT: [[LHS:%.*]] = fadd nnan double [[ARG0:%.*]], 1.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], double [[LHS]], double [[RHS:%.*]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp ord double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %lhs = fadd nnan double %arg0, 1.0 + %op = select i1 %cond, double %lhs, double %rhs + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @nnan_fadd(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_fadd( +; CHECK-NEXT: [[NNAN_ARG0:%.*]] = fadd nnan double [[ARG0:%.*]], 1.000000e+00 +; CHECK-NEXT: [[NNAN_ARG1:%.*]] = fadd nnan double [[ARG0]], 2.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = fadd double [[NNAN_ARG0]], [[NNAN_ARG1]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp uno double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan.arg0 = fadd nnan double %arg0, 1.0 + %nnan.arg1 = fadd nnan double %arg0, 2.0 + %op = fadd double %nnan.arg0, %nnan.arg1 + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @nnan_fadd_maybe_nan_lhs(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_fadd_maybe_nan_lhs( +; CHECK-NEXT: [[NNAN_ARG1:%.*]] = fadd nnan double [[ARG1:%.*]], 1.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = fadd double [[ARG0:%.*]], [[NNAN_ARG1]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp ord double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan.arg1 = fadd nnan double %arg1, 1.0 + %op = fadd double %arg0, %nnan.arg1 + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @nnan_fadd_maybe_nan_rhs(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_fadd_maybe_nan_rhs( +; CHECK-NEXT: [[NNAN_ARG0:%.*]] = fadd nnan double [[ARG0:%.*]], 1.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = fadd double [[NNAN_ARG0]], [[ARG1:%.*]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp uno double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan.arg0 = fadd nnan double %arg0, 1.0 + %op = fadd double %nnan.arg0, %arg1 + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @nnan_fmul(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_fmul( +; CHECK-NEXT: [[NNAN_ARG0:%.*]] = fadd nnan double [[ARG0:%.*]], 1.000000e+00 +; CHECK-NEXT: [[NNAN_ARG1:%.*]] = fadd nnan double [[ARG0]], 2.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = fmul double [[NNAN_ARG0]], [[NNAN_ARG1]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp ord double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan.arg0 = fadd nnan double %arg0, 1.0 + %nnan.arg1 = fadd nnan double %arg0, 2.0 + %op = fmul double %nnan.arg0, %nnan.arg1 + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @nnan_fsub(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_fsub( +; CHECK-NEXT: [[NNAN_ARG0:%.*]] = fadd nnan double [[ARG0:%.*]], 1.000000e+00 +; CHECK-NEXT: [[NNAN_ARG1:%.*]] = fadd nnan double [[ARG0]], 2.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = fsub double [[NNAN_ARG0]], [[NNAN_ARG1]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp uno double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan.arg0 = fadd nnan double %arg0, 1.0 + %nnan.arg1 = fadd nnan double %arg0, 2.0 + %op = fsub double %nnan.arg0, %nnan.arg1 + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @nnan_fneg() { +; CHECK-LABEL: @nnan_fneg( +; CHECK-NEXT: [[NNAN:%.*]] = call nnan double @func() +; CHECK-NEXT: [[OP:%.*]] = fsub double -0.000000e+00, [[NNAN]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp ord double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan = call nnan double @func() + %op = fsub double -0.0, %nnan + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @sitofp(i32 %arg0) { +; CHECK-LABEL: @sitofp( +; CHECK-NEXT: ret i1 false +; + %op = sitofp i32 %arg0 to double + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @uitofp(i32 %arg0) { +; CHECK-LABEL: @uitofp( +; CHECK-NEXT: ret i1 true +; + %op = uitofp i32 %arg0 to double + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @fpext(float %arg0) { +; CHECK-LABEL: @fpext( +; CHECK-NEXT: ret i1 false +; + %arg0.nnan = fadd nnan float %arg0, 1.0 + %op = fpext float %arg0.nnan to double + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @fpext_maybe_nan(float %arg0) { +; CHECK-LABEL: @fpext_maybe_nan( +; CHECK-NEXT: [[OP:%.*]] = fpext float [[ARG0:%.*]] to double +; CHECK-NEXT: [[TMP:%.*]] = fcmp ord double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %op = fpext float %arg0 to double + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +define i1 @fptrunc(double %arg0) { +; CHECK-LABEL: @fptrunc( +; CHECK-NEXT: ret i1 false +; + %arg0.nnan = fadd nnan double %arg0, 1.0 + %op = fptrunc double %arg0.nnan to float + %tmp = fcmp uno float %op, %op + ret i1 %tmp +} + +define i1 @fptrunc_maybe_nan(double %arg0) { +; CHECK-LABEL: @fptrunc_maybe_nan( +; CHECK-NEXT: [[OP:%.*]] = fptrunc double [[ARG0:%.*]] to float +; CHECK-NEXT: [[TMP:%.*]] = fcmp ord float [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %op = fptrunc double %arg0 to float + %tmp = fcmp ord float %op, %op + ret i1 %tmp +} + +define i1 @nnan_fdiv(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_fdiv( +; CHECK-NEXT: [[NNAN_ARG0:%.*]] = fadd nnan double [[ARG0:%.*]], 1.000000e+00 +; CHECK-NEXT: [[NNAN_ARG1:%.*]] = fadd nnan double [[ARG0]], 2.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = fdiv double [[NNAN_ARG0]], [[NNAN_ARG1]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp uno double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan.arg0 = fadd nnan double %arg0, 1.0 + %nnan.arg1 = fadd nnan double %arg0, 2.0 + %op = fdiv double %nnan.arg0, %nnan.arg1 + %tmp = fcmp uno double %op, %op + ret i1 %tmp +} + +define i1 @nnan_frem(double %arg0, double %arg1) { +; CHECK-LABEL: @nnan_frem( +; CHECK-NEXT: [[NNAN_ARG0:%.*]] = fadd nnan double [[ARG0:%.*]], 1.000000e+00 +; CHECK-NEXT: [[NNAN_ARG1:%.*]] = fadd nnan double [[ARG0]], 2.000000e+00 +; CHECK-NEXT: [[OP:%.*]] = frem double [[NNAN_ARG0]], [[NNAN_ARG1]] +; CHECK-NEXT: [[TMP:%.*]] = fcmp ord double [[OP]], [[OP]] +; CHECK-NEXT: ret i1 [[TMP]] +; + %nnan.arg0 = fadd nnan double %arg0, 1.0 + %nnan.arg1 = fadd nnan double %arg0, 2.0 + %op = frem double %nnan.arg0, %nnan.arg1 + %tmp = fcmp ord double %op, %op + ret i1 %tmp +} + +declare double @llvm.sqrt.f64(double) +declare double @llvm.fabs.f64(double) +declare double @llvm.canonicalize.f64(double) +declare double @llvm.copysign.f64(double, double) +declare double @llvm.exp.f64(double) +declare double @llvm.exp2.f64(double) +declare double @llvm.floor.f64(double) +declare double @llvm.ceil.f64(double) +declare double @llvm.trunc.f64(double) +declare double @llvm.rint.f64(double) +declare double @llvm.nearbyint.f64(double) +declare double @llvm.round.f64(double) diff --git a/llvm/test/Transforms/InstSimplify/load-relative-32.ll b/llvm/test/Transforms/InstSimplify/load-relative-32.ll new file mode 100644 index 00000000000..a38de8549db --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/load-relative-32.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32" +target triple = "i386-unknown-linux-gnu" + +@a = external global i8 + +@c1 = constant [3 x i32] [i32 0, i32 0, +i32 sub (i32 ptrtoint (i8* @a to i32), i32 ptrtoint (i32* getelementptr ([3 x i32], [3 x i32]* @c1, i32 0, i32 2) to i32)) +] + +; CHECK: @f1 +define i8* @f1() { + ; CHECK: ret i8* @a + %l = call i8* @llvm.load.relative.i32(i8* bitcast (i32* getelementptr ([3 x i32], [3 x i32]* @c1, i32 0, i32 2) to i8*), i32 0) + ret i8* %l +} + +declare i8* @llvm.load.relative.i32(i8*, i32) diff --git a/llvm/test/Transforms/InstSimplify/load-relative.ll b/llvm/test/Transforms/InstSimplify/load-relative.ll new file mode 100644 index 00000000000..3074ede2b69 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/load-relative.ll @@ -0,0 +1,75 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@a = external global i8 +@b = external global i8 + +@c1 = constant i32 trunc (i64 sub (i64 ptrtoint (i8* @a to i64), i64 ptrtoint (i32* @c1 to i64)) to i32) +@c2 = constant [7 x i32] [i32 0, i32 0, +i32 trunc (i64 sub (i64 ptrtoint (i8* @a to i64), i64 ptrtoint (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i32 0, i32 2) to i64)) to i32), +i32 trunc (i64 sub (i64 ptrtoint (i8* @b to i64), i64 ptrtoint (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i32 0, i32 2) to i64)) to i32), +i32 trunc (i64 add (i64 ptrtoint (i8* @b to i64), i64 ptrtoint (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i32 0, i32 2) to i64)) to i32), +i32 trunc (i64 sub (i64 ptrtoint (i8* @b to i64), i64 1) to i32), +i32 trunc (i64 sub (i64 0, i64 ptrtoint (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i32 0, i32 2) to i64)) to i32) +] + +; CHECK: @f1 +define i8* @f1() { + ; CHECK: ret i8* @a + %l = call i8* @llvm.load.relative.i32(i8* bitcast (i32* @c1 to i8*), i32 0) + ret i8* %l +} + +; CHECK: @f2 +define i8* @f2() { + ; CHECK: ret i8* @a + %l = call i8* @llvm.load.relative.i32(i8* bitcast (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i64 0, i64 2) to i8*), i32 0) + ret i8* %l +} + +; CHECK: @f3 +define i8* @f3() { + ; CHECK: ret i8* @b + %l = call i8* @llvm.load.relative.i64(i8* bitcast (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i64 0, i64 2) to i8*), i64 4) + ret i8* %l +} + +; CHECK: @f4 +define i8* @f4() { + ; CHECK: ret i8* % + %l = call i8* @llvm.load.relative.i32(i8* bitcast (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i64 0, i64 2) to i8*), i32 1) + ret i8* %l +} + +; CHECK: @f5 +define i8* @f5() { + ; CHECK: ret i8* % + %l = call i8* @llvm.load.relative.i32(i8* zeroinitializer, i32 0) + ret i8* %l +} + +; CHECK: @f6 +define i8* @f6() { + ; CHECK: ret i8* % + %l = call i8* @llvm.load.relative.i32(i8* bitcast (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i64 0, i64 2) to i8*), i32 8) + ret i8* %l +} + +; CHECK: @f7 +define i8* @f7() { + ; CHECK: ret i8* % + %l = call i8* @llvm.load.relative.i32(i8* bitcast (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i64 0, i64 2) to i8*), i32 12) + ret i8* %l +} + +; CHECK: @f8 +define i8* @f8() { + ; CHECK: ret i8* % + %l = call i8* @llvm.load.relative.i32(i8* bitcast (i32* getelementptr ([7 x i32], [7 x i32]* @c2, i64 0, i64 2) to i8*), i32 16) + ret i8* %l +} + +declare i8* @llvm.load.relative.i32(i8*, i32) +declare i8* @llvm.load.relative.i64(i8*, i64) diff --git a/llvm/test/Transforms/InstSimplify/load.ll b/llvm/test/Transforms/InstSimplify/load.ll new file mode 100644 index 00000000000..8b2b5a17660 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/load.ll @@ -0,0 +1,30 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +@zeroinit = constant {} zeroinitializer +@undef = constant {} undef + +define i32 @crash_on_zeroinit() { +; CHECK-LABEL: @crash_on_zeroinit( +; CHECK: ret i32 0 +; + %load = load i32, i32* bitcast ({}* @zeroinit to i32*) + ret i32 %load +} + +define i32 @crash_on_undef() { +; CHECK-LABEL: @crash_on_undef( +; CHECK: ret i32 undef +; + %load = load i32, i32* bitcast ({}* @undef to i32*) + ret i32 %load +} + +@GV = private constant [8 x i32] [i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48, i32 49] + +define <8 x i32> @partial_load() { +; CHECK-LABEL: @partial_load( +; CHECK: ret <8 x i32> <i32 0, i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48> + %load = load <8 x i32>, <8 x i32>* bitcast (i32* getelementptr ([8 x i32], [8 x i32]* @GV, i64 0, i64 -1) to <8 x i32>*) + ret <8 x i32> %load +} diff --git a/llvm/test/Transforms/InstSimplify/log-exp-intrinsic.ll b/llvm/test/Transforms/InstSimplify/log-exp-intrinsic.ll new file mode 100644 index 00000000000..826ec42b31c --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/log-exp-intrinsic.ll @@ -0,0 +1,192 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +declare double @llvm.log.f64(double) +declare double @llvm.exp.f64(double) +declare double @llvm.log2.f64(double) +declare double @llvm.exp2.f64(double) + +define double @log_reassoc_exp_strict(double %a) { +; CHECK-LABEL: @log_reassoc_exp_strict( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.exp.f64(double %a) + %2 = call reassoc double @llvm.log.f64(double %1) + ret double %2 +} + +define double @log_strict_exp_reassoc(double %a) { +; CHECK-LABEL: @log_strict_exp_reassoc( +; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.exp.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.log.f64(double [[TMP1]]) +; CHECK-NEXT: ret double [[TMP2]] +; + %1 = call reassoc double @llvm.exp.f64(double %a) + %2 = call double @llvm.log.f64(double %1) + ret double %2 +} + +define double @log_exp_log_exp(double %a) { +; CHECK-LABEL: @log_exp_log_exp( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.exp.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.log.f64(double [[TMP1]]) +; CHECK-NEXT: [[TMP3:%.*]] = call double @llvm.exp.f64(double [[TMP2]]) +; CHECK-NEXT: [[TMP4:%.*]] = call double @llvm.log.f64(double [[TMP3]]) +; CHECK-NEXT: ret double [[TMP4]] +; + %1 = call double @llvm.exp.f64(double %a) + %2 = call double @llvm.log.f64(double %1) + %3 = call double @llvm.exp.f64(double %2) + %4 = call double @llvm.log.f64(double %3) + ret double %4 +} + +define double @log_exp_log_exp_reassoc(double %a) { +; CHECK-LABEL: @log_exp_log_exp_reassoc( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.exp.f64(double %a) + %2 = call reassoc double @llvm.log.f64(double %1) + %3 = call double @llvm.exp.f64(double %2) + %4 = call reassoc double @llvm.log.f64(double %3) + ret double %4 +} + +define double @log2_reassoc_exp2_strict(double %a) { +; CHECK-LABEL: @log2_reassoc_exp2_strict( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.exp2.f64(double %a) + %2 = call reassoc double @llvm.log2.f64(double %1) + ret double %2 +} + +define double @log2_strict_exp2_reassoc(double %a) { +; CHECK-LABEL: @log2_strict_exp2_reassoc( +; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.exp2.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.log2.f64(double [[TMP1]]) +; CHECK-NEXT: ret double [[TMP2]] +; + %1 = call reassoc double @llvm.exp2.f64(double %a) + %2 = call double @llvm.log2.f64(double %1) + ret double %2 +} + +define double @log2_exp2_log2_exp2(double %a) { +; CHECK-LABEL: @log2_exp2_log2_exp2( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.exp2.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.log2.f64(double [[TMP1]]) +; CHECK-NEXT: [[TMP3:%.*]] = call double @llvm.exp2.f64(double [[TMP2]]) +; CHECK-NEXT: [[TMP4:%.*]] = call double @llvm.log2.f64(double [[TMP3]]) +; CHECK-NEXT: ret double [[TMP4]] +; + %1 = call double @llvm.exp2.f64(double %a) + %2 = call double @llvm.log2.f64(double %1) + %3 = call double @llvm.exp2.f64(double %2) + %4 = call double @llvm.log2.f64(double %3) + ret double %4 +} + +define double @log2_exp2_log2_exp2_reassoc(double %a) { +; CHECK-LABEL: @log2_exp2_log2_exp2_reassoc( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.exp2.f64(double %a) + %2 = call reassoc double @llvm.log2.f64(double %1) + %3 = call double @llvm.exp2.f64(double %2) + %4 = call reassoc double @llvm.log2.f64(double %3) + ret double %4 +} + +define double @exp_reassoc_log_strict(double %a) { +; CHECK-LABEL: @exp_reassoc_log_strict( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.log.f64(double %a) + %2 = call reassoc double @llvm.exp.f64(double %1) + ret double %2 +} + +define double @exp_strict_log_reassoc(double %a) { +; CHECK-LABEL: @exp_strict_log_reassoc( +; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.log.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.exp.f64(double [[TMP1]]) +; CHECK-NEXT: ret double [[TMP2]] +; + %1 = call reassoc double @llvm.log.f64(double %a) + %2 = call double @llvm.exp.f64(double %1) + ret double %2 +} + +define double @exp_log_exp_log(double %a) { +; CHECK-LABEL: @exp_log_exp_log( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.log.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.exp.f64(double [[TMP1]]) +; CHECK-NEXT: [[TMP3:%.*]] = call double @llvm.log.f64(double [[TMP2]]) +; CHECK-NEXT: [[TMP4:%.*]] = call double @llvm.exp.f64(double [[TMP3]]) +; CHECK-NEXT: ret double [[TMP4]] +; + %1 = call double @llvm.log.f64(double %a) + %2 = call double @llvm.exp.f64(double %1) + %3 = call double @llvm.log.f64(double %2) + %4 = call double @llvm.exp.f64(double %3) + ret double %4 +} + +define double @exp_log_exp_log_reassoc(double %a) { +; CHECK-LABEL: @exp_log_exp_log_reassoc( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.log.f64(double %a) + %2 = call reassoc double @llvm.exp.f64(double %1) + %3 = call double @llvm.log.f64(double %2) + %4 = call reassoc double @llvm.exp.f64(double %3) + ret double %4 +} + +define double @exp2_reassoc_log2_strict(double %a) { +; CHECK-LABEL: @exp2_reassoc_log2_strict( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.log2.f64(double %a) + %2 = call reassoc double @llvm.exp2.f64(double %1) + ret double %2 +} + +define double @exp2_strict_log2_reassoc(double %a) { +; CHECK-LABEL: @exp2_strict_log2_reassoc( +; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.log2.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.exp2.f64(double [[TMP1]]) +; CHECK-NEXT: ret double [[TMP2]] +; + %1 = call reassoc double @llvm.log2.f64(double %a) + %2 = call double @llvm.exp2.f64(double %1) + ret double %2 +} + +define double @exp2_log2_exp2_log2(double %a) { +; CHECK-LABEL: @exp2_log2_exp2_log2( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.log2.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.exp2.f64(double [[TMP1]]) +; CHECK-NEXT: [[TMP3:%.*]] = call double @llvm.log2.f64(double [[TMP2]]) +; CHECK-NEXT: [[TMP4:%.*]] = call double @llvm.exp2.f64(double [[TMP3]]) +; CHECK-NEXT: ret double [[TMP4]] +; + %1 = call double @llvm.log2.f64(double %a) + %2 = call double @llvm.exp2.f64(double %1) + %3 = call double @llvm.log2.f64(double %2) + %4 = call double @llvm.exp2.f64(double %3) + ret double %4 +} + +define double @exp2_log2_exp2_log2_reassoc(double %a) { +; CHECK-LABEL: @exp2_log2_exp2_log2_reassoc( +; CHECK-NEXT: ret double [[A:%.*]] +; + %1 = call double @llvm.log2.f64(double %a) + %2 = call reassoc double @llvm.exp2.f64(double %1) + %3 = call double @llvm.log2.f64(double %2) + %4 = call reassoc double @llvm.exp2.f64(double %3) + ret double %4 +} + diff --git a/llvm/test/Transforms/InstSimplify/log10-pow10-intrinsic.ll b/llvm/test/Transforms/InstSimplify/log10-pow10-intrinsic.ll new file mode 100644 index 00000000000..a5b7afde1a8 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/log10-pow10-intrinsic.ll @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instsimplify < %s | FileCheck %s + +declare double @llvm.log10.f64(double) +declare double @llvm.pow.f64(double, double) + +define double @log10_pow10(double %x) { +; CHECK-LABEL: @log10_pow10( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.pow.f64(double 1.000000e+01, double [[X:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.log10.f64(double [[TMP1]]) +; CHECK-NEXT: ret double [[TMP2]] +; + %tmp = call double @llvm.pow.f64(double 1.000000e+01, double %x) + %tmp1 = call double @llvm.log10.f64(double %tmp) + ret double %tmp1 +} + +define double @log10_strict_pow10_reassoc(double %x) { +; CHECK-LABEL: @log10_strict_pow10_reassoc( +; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.pow.f64(double 1.000000e+01, double [[X:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.log10.f64(double [[TMP1]]) +; CHECK-NEXT: ret double [[TMP2]] +; + %tmp = call reassoc double @llvm.pow.f64(double 1.000000e+01, double %x) + %tmp1 = call double @llvm.log10.f64(double %tmp) + ret double %tmp1 +} + +define double @log10_reassoc_pow10_strict(double %x) { +; CHECK-LABEL: @log10_reassoc_pow10_strict( +; CHECK-NEXT: ret double [[X:%.*]] +; + %tmp = call double @llvm.pow.f64(double 1.000000e+01, double %x) + %tmp1 = call reassoc double @llvm.log10.f64(double %tmp) + ret double %tmp1 +} + +define double @log10_pow10_reassoc(double %x) { +; CHECK-LABEL: @log10_pow10_reassoc( +; CHECK-NEXT: ret double [[X:%.*]] +; + %tmp = call reassoc double @llvm.pow.f64(double 1.000000e+01, double %x) + %tmp1 = call reassoc double @llvm.log10.f64(double %tmp) + ret double %tmp1 +} diff --git a/llvm/test/Transforms/InstSimplify/log2-pow2-intrinsic.ll b/llvm/test/Transforms/InstSimplify/log2-pow2-intrinsic.ll new file mode 100644 index 00000000000..8d8ef80db72 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/log2-pow2-intrinsic.ll @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instsimplify < %s | FileCheck %s + +declare double @llvm.log2.f64(double) +declare double @llvm.pow.f64(double, double) + +define double @log2_pow2(double %x) { +; CHECK-LABEL: @log2_pow2( +; CHECK-NEXT: [[TMP:%.*]] = call double @llvm.pow.f64(double 2.000000e+00, double [[X:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.log2.f64(double [[TMP]]) +; CHECK-NEXT: ret double [[TMP1]] +; + %tmp = call double @llvm.pow.f64(double 2.000000e+00, double %x) + %tmp1 = call double @llvm.log2.f64(double %tmp) + ret double %tmp1 +} + +define double @log2_strict_pow2_reassoc(double %x) { +; CHECK-LABEL: @log2_strict_pow2_reassoc( +; CHECK-NEXT: [[TMP:%.*]] = call reassoc double @llvm.pow.f64(double 2.000000e+00, double [[X:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.log2.f64(double [[TMP]]) +; CHECK-NEXT: ret double [[TMP1]] +; + %tmp = call reassoc double @llvm.pow.f64(double 2.000000e+00, double %x) + %tmp1 = call double @llvm.log2.f64(double %tmp) + ret double %tmp1 +} + +define double @log2_reassoc_pow2_strict(double %x) { +; CHECK-LABEL: @log2_reassoc_pow2_strict( +; CHECK-NEXT: ret double [[X:%.*]] +; + %tmp = call double @llvm.pow.f64(double 2.000000e+00, double %x) + %tmp1 = call reassoc double @llvm.log2.f64(double %tmp) + ret double %tmp1 +} + +define double @log2_pow2_reassoc(double %x) { +; CHECK-LABEL: @log2_pow2_reassoc( +; CHECK-NEXT: ret double [[X:%.*]] +; + %tmp = call reassoc double @llvm.pow.f64(double 2.000000e+00, double %x) + %tmp1 = call reassoc double @llvm.log2.f64(double %tmp) + ret double %tmp1 +} diff --git a/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll b/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll new file mode 100644 index 00000000000..e1288e52dda --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll @@ -0,0 +1,183 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; Cycle through commuted variants where one operand of fcmp ord/uno is +; known not-a-NAN and the other is repeated in the logically-connected fcmp. + +define i1 @ord1(float %x, float %y) { +; CHECK-LABEL: @ord1( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord float %x, %y +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = fcmp ord float 0.0, %x + %cmp2 = fcmp ord float %x, %y + %r = and i1 %cmp1, %cmp2 + ret i1 %r +} + +define i1 @ord2(double %x, double %y) { +; CHECK-LABEL: @ord2( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord double %y, %x +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = fcmp ord double 42.0, %x + %cmp2 = fcmp ord double %y, %x + %r = and i1 %cmp1, %cmp2 + ret i1 %r +} + +define <2 x i1> @ord3(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @ord3( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord <2 x float> %x, %y +; CHECK-NEXT: ret <2 x i1> [[CMP2]] +; + %cmp1 = fcmp ord <2 x float> %x, zeroinitializer + %cmp2 = fcmp ord <2 x float> %x, %y + %r = and <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + +define <2 x i1> @ord4(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @ord4( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord <2 x double> %y, %x +; CHECK-NEXT: ret <2 x i1> [[CMP2]] +; + %cmp1 = fcmp ord <2 x double> %x, <double 42.0, double 42.0> + %cmp2 = fcmp ord <2 x double> %y, %x + %r = and <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + +define i1 @ord5(float %x, float %y) { +; CHECK-LABEL: @ord5( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord float %x, %y +; CHECK-NEXT: ret i1 [[CMP1]] +; + %nnan = fdiv nnan float %x, %y + %cmp1 = fcmp ord float %x, %y + %cmp2 = fcmp ord float %nnan, %x + %r = and i1 %cmp1, %cmp2 + ret i1 %r +} + +define i1 @ord6(double %x, double %y) { +; CHECK-LABEL: @ord6( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double %y, %x +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = fcmp ord double %y, %x + %cmp2 = fcmp ord double 42.0, %x + %r = and i1 %cmp1, %cmp2 + ret i1 %r +} + +define <2 x i1> @ord7(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @ord7( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord <2 x float> %x, %y +; CHECK-NEXT: ret <2 x i1> [[CMP1]] +; + %cmp1 = fcmp ord <2 x float> %x, %y + %cmp2 = fcmp ord <2 x float> %x, zeroinitializer + %r = and <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + +define <2 x i1> @ord8(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @ord8( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord <2 x double> %y, %x +; CHECK-NEXT: ret <2 x i1> [[CMP1]] +; + %cmp1 = fcmp ord <2 x double> %y, %x + %cmp2 = fcmp ord <2 x double> %x, <double 0.0, double 42.0> + %r = and <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + +define i1 @uno1(float %x, float %y) { +; CHECK-LABEL: @uno1( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno float %x, %y +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = fcmp uno float 0.0, %x + %cmp2 = fcmp uno float %x, %y + %r = or i1 %cmp1, %cmp2 + ret i1 %r +} + +define i1 @uno2(double %x, double %y) { +; CHECK-LABEL: @uno2( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno double %y, %x +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = fcmp uno double 42.0, %x + %cmp2 = fcmp uno double %y, %x + %r = or i1 %cmp1, %cmp2 + ret i1 %r +} + +define <2 x i1> @uno3(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @uno3( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno <2 x float> %x, %y +; CHECK-NEXT: ret <2 x i1> [[CMP2]] +; + %cmp1 = fcmp uno <2 x float> %x, zeroinitializer + %cmp2 = fcmp uno <2 x float> %x, %y + %r = or <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + +define <2 x i1> @uno4(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @uno4( +; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno <2 x double> %y, %x +; CHECK-NEXT: ret <2 x i1> [[CMP2]] +; + %cmp1 = fcmp uno <2 x double> %x, <double 42.0, double 42.0> + %cmp2 = fcmp uno <2 x double> %y, %x + %r = or <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + +define i1 @uno5(float %x, float %y) { +; CHECK-LABEL: @uno5( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno float %x, %y +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = fcmp uno float %x, %y + %cmp2 = fcmp uno float 0.0, %x + %r = or i1 %cmp1, %cmp2 + ret i1 %r +} + +define i1 @uno6(double %x, double %y) { +; CHECK-LABEL: @uno6( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno double %y, %x +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = fcmp uno double %y, %x + %cmp2 = fcmp uno double 42.0, %x + %r = or i1 %cmp1, %cmp2 + ret i1 %r +} + +define <2 x i1> @uno7(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @uno7( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <2 x float> %x, %y +; CHECK-NEXT: ret <2 x i1> [[CMP1]] +; + %nnan = fdiv nnan <2 x float> %x, %y + %cmp1 = fcmp uno <2 x float> %x, %y + %cmp2 = fcmp uno <2 x float> %x, %nnan + %r = or <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + +define <2 x i1> @uno8(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @uno8( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <2 x double> %y, %x +; CHECK-NEXT: ret <2 x i1> [[CMP1]] +; + %cmp1 = fcmp uno <2 x double> %y, %x + %cmp2 = fcmp uno <2 x double> %x, <double 0x7ff0000000000000, double 42.0> + %r = or <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %r +} + diff --git a/llvm/test/Transforms/InstSimplify/maxmin.ll b/llvm/test/Transforms/InstSimplify/maxmin.ll new file mode 100644 index 00000000000..3fcbfec2f63 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/maxmin.ll @@ -0,0 +1,302 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i1 @max1(i32 %x, i32 %y) { +; CHECK-LABEL: @max1( +; CHECK: ret i1 false +; + %c = icmp sgt i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp slt i32 %m, %x + ret i1 %r +} + +define i1 @max2(i32 %x, i32 %y) { +; CHECK-LABEL: @max2( +; CHECK: ret i1 true +; + %c = icmp sge i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp sge i32 %m, %x + ret i1 %r +} + +define i1 @max3(i32 %x, i32 %y) { +; CHECK-LABEL: @max3( +; CHECK: ret i1 false +; + %c = icmp ugt i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp ult i32 %m, %x + ret i1 %r +} + +define i1 @max4(i32 %x, i32 %y) { +; CHECK-LABEL: @max4( +; CHECK: ret i1 true +; + %c = icmp uge i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp uge i32 %m, %x + ret i1 %r +} + +define i1 @max5(i32 %x, i32 %y) { +; CHECK-LABEL: @max5( +; CHECK: ret i1 false +; + %c = icmp sgt i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp sgt i32 %x, %m + ret i1 %r +} + +define i1 @max6(i32 %x, i32 %y) { +; CHECK-LABEL: @max6( +; CHECK: ret i1 true +; + %c = icmp sge i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp sle i32 %x, %m + ret i1 %r +} + +define i1 @max7(i32 %x, i32 %y) { +; CHECK-LABEL: @max7( +; CHECK: ret i1 false +; + %c = icmp ugt i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp ugt i32 %x, %m + ret i1 %r +} + +define i1 @max8(i32 %x, i32 %y) { +; CHECK-LABEL: @max8( +; CHECK: ret i1 true +; + %c = icmp uge i32 %x, %y + %m = select i1 %c, i32 %x, i32 %y + %r = icmp ule i32 %x, %m + ret i1 %r +} + +define i1 @min1(i32 %x, i32 %y) { +; CHECK-LABEL: @min1( +; CHECK: ret i1 false +; + %c = icmp sgt i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp sgt i32 %m, %x + ret i1 %r +} + +define i1 @min2(i32 %x, i32 %y) { +; CHECK-LABEL: @min2( +; CHECK: ret i1 true +; + %c = icmp sge i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp sle i32 %m, %x + ret i1 %r +} + +define i1 @min3(i32 %x, i32 %y) { +; CHECK-LABEL: @min3( +; CHECK: ret i1 false +; + %c = icmp ugt i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp ugt i32 %m, %x + ret i1 %r +} + +define i1 @min4(i32 %x, i32 %y) { +; CHECK-LABEL: @min4( +; CHECK: ret i1 true +; + %c = icmp uge i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp ule i32 %m, %x + ret i1 %r +} + +define i1 @min5(i32 %x, i32 %y) { +; CHECK-LABEL: @min5( +; CHECK: ret i1 false +; + %c = icmp sgt i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp slt i32 %x, %m + ret i1 %r +} + +define i1 @min6(i32 %x, i32 %y) { +; CHECK-LABEL: @min6( +; CHECK: ret i1 true +; + %c = icmp sge i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp sge i32 %x, %m + ret i1 %r +} + +define i1 @min7(i32 %x, i32 %y) { +; CHECK-LABEL: @min7( +; CHECK: ret i1 false +; + %c = icmp ugt i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp ult i32 %x, %m + ret i1 %r +} + +define i1 @min8(i32 %x, i32 %y) { +; CHECK-LABEL: @min8( +; CHECK: ret i1 true +; + %c = icmp uge i32 %x, %y + %m = select i1 %c, i32 %y, i32 %x + %r = icmp uge i32 %x, %m + ret i1 %r +} + +define i1 @maxmin1(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin1( +; CHECK: ret i1 true +; + %c1 = icmp sge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp sge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp sge i32 %max, %min + ret i1 %c +} + +define i1 @maxmin2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin2( +; CHECK: ret i1 false +; + %c1 = icmp sge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp sge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp sgt i32 %min, %max + ret i1 %c +} + +define i1 @maxmin3(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin3( +; CHECK: ret i1 true +; + %c1 = icmp sge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp sge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp sle i32 %min, %max + ret i1 %c +} + +define i1 @maxmin4(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin4( +; CHECK: ret i1 false +; + %c1 = icmp sge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp sge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp slt i32 %max, %min + ret i1 %c +} + +define i1 @maxmin5(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin5( +; CHECK: ret i1 true +; + %c1 = icmp uge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp uge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp uge i32 %max, %min + ret i1 %c +} + +define i1 @maxmin6(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin6( +; CHECK: ret i1 false +; + %c1 = icmp uge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp uge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp ugt i32 %min, %max + ret i1 %c +} + +define i1 @maxmin7(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin7( +; CHECK: ret i1 true +; + %c1 = icmp uge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp uge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp ule i32 %min, %max + ret i1 %c +} + +define i1 @maxmin8(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @maxmin8( +; CHECK: ret i1 false +; + %c1 = icmp uge i32 %x, %y + %max = select i1 %c1, i32 %x, i32 %y + %c2 = icmp uge i32 %x, %z + %min = select i1 %c2, i32 %z, i32 %x + %c = icmp ult i32 %max, %min + ret i1 %c +} + +define i1 @eqcmp1(i32 %x, i32 %y) { +; CHECK-LABEL: @eqcmp1( +; CHECK: [[C:%.*]] = icmp sge i32 %x, %y +; CHECK-NEXT: ret i1 [[C]] +; + %c = icmp sge i32 %x, %y + %max = select i1 %c, i32 %x, i32 %y + %r = icmp eq i32 %max, %x + ret i1 %r +} + +define i1 @eqcmp2(i32 %x, i32 %y) { +; CHECK-LABEL: @eqcmp2( +; CHECK: [[C:%.*]] = icmp sge i32 %x, %y +; CHECK-NEXT: ret i1 [[C]] +; + %c = icmp sge i32 %x, %y + %max = select i1 %c, i32 %x, i32 %y + %r = icmp eq i32 %x, %max + ret i1 %r +} + +define i1 @eqcmp3(i32 %x, i32 %y) { +; CHECK-LABEL: @eqcmp3( +; CHECK: [[C:%.*]] = icmp uge i32 %x, %y +; CHECK-NEXT: ret i1 [[C]] +; + %c = icmp uge i32 %x, %y + %max = select i1 %c, i32 %x, i32 %y + %r = icmp eq i32 %max, %x + ret i1 %r +} + +define i1 @eqcmp4(i32 %x, i32 %y) { +; CHECK-LABEL: @eqcmp4( +; CHECK: [[C:%.*]] = icmp uge i32 %x, %y +; CHECK-NEXT: ret i1 [[C]] +; + %c = icmp uge i32 %x, %y + %max = select i1 %c, i32 %x, i32 %y + %r = icmp eq i32 %x, %max + ret i1 %r +} diff --git a/llvm/test/Transforms/InstSimplify/mul.ll b/llvm/test/Transforms/InstSimplify/mul.ll new file mode 100644 index 00000000000..71410cd0ca3 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/mul.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define <2 x i1> @test1(<2 x i1> %a) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %b = and <2 x i1> %a, <i1 true, i1 false> + %res = mul <2 x i1> %b, <i1 false, i1 true> + ret <2 x i1> %res +} + +define i32 @mul_by_1(i32 %A) { +; CHECK-LABEL: @mul_by_1( +; CHECK-NEXT: ret i32 [[A:%.*]] +; + %B = mul i32 %A, 1 + ret i32 %B +} + +define i32 @mul_by_0(i32 %A) { +; CHECK-LABEL: @mul_by_0( +; CHECK-NEXT: ret i32 0 +; + %B = mul i32 %A, 0 + ret i32 %B +} + +define <16 x i8> @mul_by_0_vec(<16 x i8> %a) { +; CHECK-LABEL: @mul_by_0_vec( +; CHECK-NEXT: ret <16 x i8> zeroinitializer +; + %b = mul <16 x i8> %a, zeroinitializer + ret <16 x i8> %b +} + +define <2 x i8> @mul_by_0_vec_undef_elt(<2 x i8> %a) { +; CHECK-LABEL: @mul_by_0_vec_undef_elt( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %b = mul <2 x i8> %a, <i8 undef, i8 0> + ret <2 x i8> %b +} + diff --git a/llvm/test/Transforms/InstSimplify/negate.ll b/llvm/test/Transforms/InstSimplify/negate.ll new file mode 100644 index 00000000000..ec18826073c --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/negate.ll @@ -0,0 +1,74 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @negate_nuw(i32 %x) { +; CHECK-LABEL: @negate_nuw( +; CHECK-NEXT: ret i32 0 +; + %neg = sub nuw i32 0, %x + ret i32 %neg +} + +define <2 x i32> @negate_nuw_vec(<2 x i32> %x) { +; CHECK-LABEL: @negate_nuw_vec( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %neg = sub nuw <2 x i32> zeroinitializer, %x + ret <2 x i32> %neg +} + +define <2 x i32> @negate_nuw_vec_undef_elt(<2 x i32> %x) { +; CHECK-LABEL: @negate_nuw_vec_undef_elt( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %neg = sub nuw <2 x i32> <i32 0, i32 undef>, %x + ret <2 x i32> %neg +} + +define i8 @negate_zero_or_minsigned_nsw(i8 %x) { +; CHECK-LABEL: @negate_zero_or_minsigned_nsw( +; CHECK-NEXT: ret i8 0 +; + %signbit = and i8 %x, 128 + %neg = sub nsw i8 0, %signbit + ret i8 %neg +} + +define <2 x i8> @negate_zero_or_minsigned_nsw_vec(<2 x i8> %x) { +; CHECK-LABEL: @negate_zero_or_minsigned_nsw_vec( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %signbit = shl <2 x i8> %x, <i8 7, i8 7> + %neg = sub nsw <2 x i8> zeroinitializer, %signbit + ret <2 x i8> %neg +} + +define <2 x i8> @negate_zero_or_minsigned_nsw_vec_undef_elt(<2 x i8> %x) { +; CHECK-LABEL: @negate_zero_or_minsigned_nsw_vec_undef_elt( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %signbit = shl <2 x i8> %x, <i8 7, i8 7> + %neg = sub nsw <2 x i8> <i8 undef, i8 0>, %signbit + ret <2 x i8> %neg +} + +define i8 @negate_zero_or_minsigned(i8 %x) { +; CHECK-LABEL: @negate_zero_or_minsigned( +; CHECK-NEXT: [[SIGNBIT:%.*]] = shl i8 [[X:%.*]], 7 +; CHECK-NEXT: ret i8 [[SIGNBIT]] +; + %signbit = shl i8 %x, 7 + %neg = sub i8 0, %signbit + ret i8 %neg +} + +define <2 x i8> @negate_zero_or_minsigned_vec(<2 x i8> %x) { +; CHECK-LABEL: @negate_zero_or_minsigned_vec( +; CHECK-NEXT: [[SIGNBIT:%.*]] = and <2 x i8> [[X:%.*]], <i8 -128, i8 -128> +; CHECK-NEXT: ret <2 x i8> [[SIGNBIT]] +; + %signbit = and <2 x i8> %x, <i8 128, i8 128> + %neg = sub <2 x i8> zeroinitializer, %signbit + ret <2 x i8> %neg +} + diff --git a/llvm/test/Transforms/InstSimplify/noalias-ptr.ll b/llvm/test/Transforms/InstSimplify/noalias-ptr.ll new file mode 100644 index 00000000000..59b1dfa8de3 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/noalias-ptr.ll @@ -0,0 +1,259 @@ +; RUN: opt -instsimplify -S < %s | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@g1 = global i32 0, align 4 +@g2 = internal global i32 0, align 4 +@g3 = unnamed_addr global i32 0, align 4 +@g4 = hidden global i32 0, align 4 +@g5 = protected global i32 0, align 4 +@g6 = thread_local unnamed_addr global i32 0, align 4 + +; Make sure we can simplify away a pointer comparison between +; dynamically-allocated memory and a local stack allocation. +; void p() +; { +; int *mData; +; int mStackData[10]; +; mData = new int[12]; +; if (mData != mStackData) { +; delete[] mData; +; } +; } + +define void @_Z2p1v() #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = tail call noalias i8* @_Znam(i64 48) #4 + %3 = bitcast i8* %2 to i32* + %4 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %5 = icmp eq i32* %3, %4 + br i1 %5, label %7, label %6 + +; CHECK-LABEL: @_Z2p1v +; CHECK-NOT: icmp +; CHECK: ret void + +; <label>:6 ; preds = %0 + call void @_ZdaPv(i8* %2) #5 + br label %7 + +; <label>:7 ; preds = %0, %6 + ret void +} + +; Also check a more-complicated case with multiple underlying objects. + +define void @_Z2p2bb(i1 zeroext %b1, i1 zeroext %b2) #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %3 = select i1 %b1, i32* %2, i32* @g2 + %4 = tail call noalias i8* @_Znam(i64 48) #4 + %5 = tail call noalias i8* @_Znam(i64 48) #4 + %.v = select i1 %b2, i8* %4, i8* %5 + %6 = bitcast i8* %.v to i32* + %7 = icmp eq i32* %6, %3 + br i1 %7, label %9, label %8 + +; CHECK-LABEL: @_Z2p2bb +; CHECK-NOT: icmp +; CHECK: ret void + +; <label>:8 ; preds = %0 + call void @_ZdaPv(i8* %4) #5 + call void @_ZdaPv(i8* %5) #5 + br label %9 + +; <label>:9 ; preds = %0, %8 + ret void +} + +define void @_Z2p4bb(i1 zeroext %b1, i1 zeroext %b2) #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %3 = select i1 %b1, i32* %2, i32* @g3 + %4 = tail call noalias i8* @_Znam(i64 48) #4 + %5 = tail call noalias i8* @_Znam(i64 48) #4 + %.v = select i1 %b2, i8* %4, i8* %5 + %6 = bitcast i8* %.v to i32* + %7 = icmp eq i32* %6, %3 + br i1 %7, label %9, label %8 + +; CHECK-LABEL: @_Z2p4bb +; CHECK-NOT: icmp +; CHECK: ret void + +; <label>:8 ; preds = %0 + call void @_ZdaPv(i8* %4) #5 + call void @_ZdaPv(i8* %5) #5 + br label %9 + +; <label>:9 ; preds = %0, %8 + ret void +} + +define void @_Z2p5bb(i1 zeroext %b1, i1 zeroext %b2) #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %3 = select i1 %b1, i32* %2, i32* @g4 + %4 = tail call noalias i8* @_Znam(i64 48) #4 + %5 = tail call noalias i8* @_Znam(i64 48) #4 + %.v = select i1 %b2, i8* %4, i8* %5 + %6 = bitcast i8* %.v to i32* + %7 = icmp eq i32* %6, %3 + br i1 %7, label %9, label %8 + +; CHECK-LABEL: @_Z2p5bb +; CHECK-NOT: icmp +; CHECK: ret void + +; <label>:8 ; preds = %0 + call void @_ZdaPv(i8* %4) #5 + call void @_ZdaPv(i8* %5) #5 + br label %9 + +; <label>:9 ; preds = %0, %8 + ret void +} + +define void @_Z2p6bb(i1 zeroext %b1, i1 zeroext %b2) #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %3 = select i1 %b1, i32* %2, i32* @g5 + %4 = tail call noalias i8* @_Znam(i64 48) #4 + %5 = tail call noalias i8* @_Znam(i64 48) #4 + %.v = select i1 %b2, i8* %4, i8* %5 + %6 = bitcast i8* %.v to i32* + %7 = icmp eq i32* %6, %3 + br i1 %7, label %9, label %8 + +; CHECK-LABEL: @_Z2p6bb +; CHECK-NOT: icmp +; CHECK: ret void + +; <label>:8 ; preds = %0 + call void @_ZdaPv(i8* %4) #5 + call void @_ZdaPv(i8* %5) #5 + br label %9 + +; <label>:9 ; preds = %0, %8 + ret void +} + +; Here's another case involving multiple underlying objects, but this time we +; must keep the comparison (it might involve a regular pointer-typed function +; argument). + +define void @_Z4nopebbPi(i1 zeroext %b1, i1 zeroext %b2, i32* readnone %q) #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %3 = select i1 %b1, i32* %2, i32* %q + %4 = tail call noalias i8* @_Znam(i64 48) #4 + %5 = tail call noalias i8* @_Znam(i64 48) #4 + %.v = select i1 %b2, i8* %4, i8* %5 + %6 = bitcast i8* %.v to i32* + %7 = icmp eq i32* %6, %3 + br i1 %7, label %9, label %8 + +; CHECK-LABEL: @_Z4nopebbPi +; CHECK: icmp +; CHECK: ret void + +; <label>:8 ; preds = %0 + call void @_ZdaPv(i8* %4) #5 + call void @_ZdaPv(i8* %5) #5 + br label %9 + +; <label>:9 ; preds = %0, %8 + ret void +} + +define void @_Z2p3bb(i1 zeroext %b1, i1 zeroext %b2) #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %3 = select i1 %b1, i32* %2, i32* @g1 + %4 = tail call noalias i8* @_Znam(i64 48) #4 + %5 = tail call noalias i8* @_Znam(i64 48) #4 + %.v = select i1 %b2, i8* %4, i8* %5 + %6 = bitcast i8* %.v to i32* + %7 = icmp eq i32* %6, %3 + br i1 %7, label %9, label %8 + +; CHECK-LABEL: @_Z2p3bb +; CHECK: icmp +; CHECK: ret void + +; <label>:8 ; preds = %0 + call void @_ZdaPv(i8* %4) #5 + call void @_ZdaPv(i8* %5) #5 + br label %9 + +; <label>:9 ; preds = %0, %8 + ret void +} + +define void @_Z2p7bb(i1 zeroext %b1, i1 zeroext %b2) #0 { + %mStackData = alloca [10 x i32], align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %3 = select i1 %b1, i32* %2, i32* @g6 + %4 = tail call noalias i8* @_Znam(i64 48) #4 + %5 = tail call noalias i8* @_Znam(i64 48) #4 + %.v = select i1 %b2, i8* %4, i8* %5 + %6 = bitcast i8* %.v to i32* + %7 = icmp eq i32* %6, %3 + br i1 %7, label %9, label %8 + +; CHECK-LABEL: @_Z2p7bb +; CHECK: icmp +; CHECK: ret void + +; <label>:8 ; preds = %0 + call void @_ZdaPv(i8* %4) #5 + call void @_ZdaPv(i8* %5) #5 + br label %9 + +; <label>:9 ; preds = %0, %8 + ret void +} + +define void @_Z2p2v(i32 %c) #0 { + %mStackData = alloca [10 x i32], i32 %c, align 16 + %1 = bitcast [10 x i32]* %mStackData to i8* + %2 = tail call noalias i8* @_Znam(i64 48) #4 + %3 = bitcast i8* %2 to i32* + %4 = getelementptr inbounds [10 x i32], [10 x i32]* %mStackData, i64 0, i64 0 + %5 = icmp eq i32* %3, %4 + br i1 %5, label %7, label %6 + +; CHECK-LABEL: @_Z2p2v +; CHECK: icmp +; CHECK: ret void + +; <label>:6 ; preds = %0 + call void @_ZdaPv(i8* %2) #5 + br label %7 + +; <label>:7 ; preds = %0, %6 + ret void +} + +; Function Attrs: nobuiltin +declare noalias i8* @_Znam(i64) #2 + +; Function Attrs: nobuiltin nounwind +declare void @_ZdaPv(i8*) #3 + +attributes #0 = { uwtable } +attributes #1 = { nounwind } +attributes #2 = { nobuiltin } +attributes #3 = { nobuiltin nounwind } +attributes #4 = { builtin } +attributes #5 = { builtin nounwind } + diff --git a/llvm/test/Transforms/InstSimplify/or-icmps-same-ops.ll b/llvm/test/Transforms/InstSimplify/or-icmps-same-ops.ll new file mode 100644 index 00000000000..326b1e158c0 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/or-icmps-same-ops.ll @@ -0,0 +1,1239 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; There are 10 * 10 combinations of icmp predicates that can be OR'd together. +; The majority of these can be simplified to always true or just one of the icmps. + +define i1 @eq_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_eq( +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ne( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_sge( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_sle( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_uge( +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ule( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @eq_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @eq_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp eq i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @ne_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_eq( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ne( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_sge( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_sle( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_uge( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ule( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ne_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ne_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ne i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @sge_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ne( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_sge( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_sle( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_slt( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sge_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @sge_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sge i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @sgt_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ne( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_sge( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_sgt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_sle( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sgt_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @sgt_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sgt i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @sle_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ne( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_sge( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_sgt( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_sle( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @sle_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @sle_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp sle i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @slt_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ne( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_sge( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_sle( +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_slt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_uge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ule( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @slt_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @slt_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp slt i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @uge_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ne( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_uge( +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ule( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @uge_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @uge_ult( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp uge i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @ugt_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ne( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_uge( +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ugt( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ule( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ugt_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ugt_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ugt i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @ule_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ne( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_uge( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ugt( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ule( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ule_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ule_ult( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP1]] +; + %cmp1 = icmp ule i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; + +define i1 @ult_eq(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_eq( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp eq i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_ne(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ne( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ne i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_sge(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_sge( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp sge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_sgt(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_sgt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp sgt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_sle(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_sle( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp sle i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_slt(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_slt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp slt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_uge(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_uge( +; CHECK-NEXT: ret i1 true +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp uge i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_ugt(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ugt( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ugt i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_ule(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ule( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ule i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_ult(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ult( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ult i8 %a, %b + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +; Check a couple of vector variants to make sure those work too. + +define <2 x i1> @ult_uge_vec(<2 x i8> %a, <2 x i8> %b) { +; CHECK-LABEL: @ult_uge_vec( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %cmp1 = icmp ult <2 x i8> %a, %b + %cmp2 = icmp uge <2 x i8> %a, %b + %or = or <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %or +} + +define <2 x i1> @ult_ule_vec(<2 x i8> %a, <2 x i8> %b) { +; CHECK-LABEL: @ult_ule_vec( +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule <2 x i8> %a, %b +; CHECK-NEXT: ret <2 x i1> [[CMP2]] +; + %cmp1 = icmp ult <2 x i8> %a, %b + %cmp2 = icmp ule <2 x i8> %a, %b + %or = or <2 x i1> %cmp1, %cmp2 + ret <2 x i1> %or +} + +define i1 @ult_ne_swap(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ne_swap( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 %b, %a +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp ne i8 %b, %a + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @ult_ule_swap(i8 %a, i8 %b) { +; CHECK-LABEL: @ult_ule_swap( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 %b, %a +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[OR]] +; + %cmp1 = icmp ult i8 %a, %b + %cmp2 = icmp uge i8 %b, %a + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + diff --git a/llvm/test/Transforms/InstSimplify/or.ll b/llvm/test/Transforms/InstSimplify/or.ll new file mode 100644 index 00000000000..20f67769eed --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/or.ll @@ -0,0 +1,221 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @test1(i32 %A) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: ret i32 %A +; + %B = or i32 %A, 0 + ret i32 %B +} + +define i32 @all_ones(i32 %A) { +; CHECK-LABEL: @all_ones( +; CHECK-NEXT: ret i32 -1 +; + %B = or i32 %A, -1 + ret i32 %B +} + +define <3 x i8> @all_ones_vec_with_undef_elt(<3 x i8> %A) { +; CHECK-LABEL: @all_ones_vec_with_undef_elt( +; CHECK-NEXT: ret <3 x i8> <i8 -1, i8 -1, i8 -1> +; + %B = or <3 x i8> %A, <i8 -1, i8 undef, i8 -1> + ret <3 x i8> %B +} + +define i1 @test3(i1 %A) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: ret i1 %A +; + %B = or i1 %A, false + ret i1 %B +} + +define i1 @test4(i1 %A) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: ret i1 true +; + %B = or i1 %A, true + ret i1 %B +} + +define i1 @test5(i1 %A) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: ret i1 %A +; + %B = or i1 %A, %A + ret i1 %B +} + +define i32 @test6(i32 %A) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: ret i32 %A +; + %B = or i32 %A, %A + ret i32 %B +} + +; A | ~A == -1 +define i32 @test7(i32 %A) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: ret i32 -1 +; + %NotA = xor i32 %A, -1 + %B = or i32 %A, %NotA + ret i32 %B +} + +define i8 @test8(i8 %A) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: ret i8 -1 +; + %B = or i8 %A, -2 + %C = or i8 %B, 1 + ret i8 %C +} + +; Test that (A|c1)|(B|c2) == (A|B)|(c1|c2) +define i8 @test9(i8 %A, i8 %B) { +; CHECK-LABEL: @test9( +; CHECK-NEXT: ret i8 -1 +; + %C = or i8 %A, 1 + %D = or i8 %B, -2 + %E = or i8 %C, %D + ret i8 %E +} + +define i8 @test10(i8 %A) { +; CHECK-LABEL: @test10( +; CHECK-NEXT: ret i8 -2 +; + %B = or i8 %A, 1 + %C = and i8 %B, -2 + ; (X & C1) | C2 --> (X | C2) & (C1|C2) + %D = or i8 %C, -2 + ret i8 %D +} + +define i8 @test11(i8 %A) { +; CHECK-LABEL: @test11( +; CHECK-NEXT: ret i8 -1 +; + %B = or i8 %A, -2 + %C = xor i8 %B, 13 + ; (X ^ C1) | C2 --> (X | C2) ^ (C1&~C2) + %D = or i8 %C, 1 + %E = xor i8 %D, 12 + ret i8 %E +} + +; Test the case where integer BitWidth <= 64 && BitWidth % 2 != 0. +define i39 @test1_apint(i39 %V, i39 %M) { +; CHECK-LABEL: @test1_apint( +; CHECK: [[N:%.*]] = and i39 %M, -274877906944 +; CHECK-NEXT: [[A:%.*]] = add i39 %V, [[N]] +; CHECK-NEXT: ret i39 [[A]] +; + ;; If we have: ((V + N) & C1) | (V & C2) + ;; .. and C2 = ~C1 and C2 is 0+1+ and (N & C2) == 0 + ;; replace with V+N. + %C1 = xor i39 274877906943, -1 ;; C2 = 274877906943 + %N = and i39 %M, 274877906944 + %A = add i39 %V, %N + %B = and i39 %A, %C1 + %D = and i39 %V, 274877906943 + %R = or i39 %B, %D + ret i39 %R +} + +define i7 @test2_apint(i7 %X) { +; CHECK-LABEL: @test2_apint( +; CHECK: ret i7 %X +; + %Y = or i7 %X, 0 + ret i7 %Y +} + +define i17 @test3_apint(i17 %X) { +; CHECK-LABEL: @test3_apint( +; CHECK: ret i17 -1 +; + %Y = or i17 %X, -1 + ret i17 %Y +} + +; Test the case where Integer BitWidth > 64 && BitWidth <= 1024. +define i399 @test4_apint(i399 %V, i399 %M) { +; CHECK-LABEL: @test4_apint( +; CHECK: [[N:%.*]] = and i399 %M, 18446742974197923840 +; CHECK-NEXT: [[A:%.*]] = add i399 %V, [[N]] +; CHECK-NEXT: ret i399 [[A]] +; + ;; If we have: ((V + N) & C1) | (V & C2) + ;; .. and C2 = ~C1 and C2 is 0+1+ and (N & C2) == 0 + ;; replace with V+N. + %C1 = xor i399 274877906943, -1 ;; C2 = 274877906943 + %N = and i399 %M, 18446742974197923840 + %A = add i399 %V, %N + %B = and i399 %A, %C1 + %D = and i399 %V, 274877906943 + %R = or i399 %D, %B + ret i399 %R +} + +define i777 @test5_apint(i777 %X) { +; CHECK-LABEL: @test5_apint( +; CHECK: ret i777 %X +; + %Y = or i777 %X, 0 + ret i777 %Y +} + +define i117 @test6_apint(i117 %X) { +; CHECK-LABEL: @test6_apint( +; CHECK: ret i117 -1 +; + %Y = or i117 %X, -1 + ret i117 %Y +} + +; Test the case where integer BitWidth <= 64 && BitWidth % 2 != 0. +; Vector version of test1_apint with the add commuted +define <2 x i39> @test7_apint(<2 x i39> %V, <2 x i39> %M) { +; CHECK-LABEL: @test7_apint( +; CHECK-NEXT: [[N:%.*]] = and <2 x i39> [[M:%.*]], <i39 -274877906944, i39 -274877906944> +; CHECK-NEXT: [[A:%.*]] = add <2 x i39> [[N]], [[V:%.*]] +; CHECK-NEXT: ret <2 x i39> [[A]] +; + ;; If we have: ((V + N) & C1) | (V & C2) + ;; .. and C2 = ~C1 and C2 is 0+1+ and (N & C2) == 0 + ;; replace with V+N. + %C1 = xor <2 x i39> <i39 274877906943, i39 274877906943>, <i39 -1, i39 -1> ;; C2 = 274877906943 + %N = and <2 x i39> %M, <i39 274877906944, i39 274877906944> + %A = add <2 x i39> %N, %V + %B = and <2 x i39> %A, %C1 + %D = and <2 x i39> %V, <i39 274877906943, i39 274877906943> + %R = or <2 x i39> %B, %D + ret <2 x i39> %R +} + +; Test the case where Integer BitWidth > 64 && BitWidth <= 1024. +; Vector version of test4_apint with the add and the or commuted +define <2 x i399> @test8_apint(<2 x i399> %V, <2 x i399> %M) { +; CHECK-LABEL: @test8_apint( +; CHECK-NEXT: [[N:%.*]] = and <2 x i399> [[M:%.*]], <i399 18446742974197923840, i399 18446742974197923840> +; CHECK-NEXT: [[A:%.*]] = add <2 x i399> [[N]], [[V:%.*]] +; CHECK-NEXT: ret <2 x i399> [[A]] +; + ;; If we have: ((V + N) & C1) | (V & C2) + ;; .. and C2 = ~C1 and C2 is 0+1+ and (N & C2) == 0 + ;; replace with V+N. + %C1 = xor <2 x i399> <i399 274877906943, i399 274877906943>, <i399 -1, i399 -1> ;; C2 = 274877906943 + %N = and <2 x i399> %M, <i399 18446742974197923840, i399 18446742974197923840> + %A = add <2 x i399> %N, %V + %B = and <2 x i399> %A, %C1 + %D = and <2 x i399> %V, <i399 274877906943, i399 274877906943> + %R = or <2 x i399> %D, %B + ret <2 x i399> %R +} diff --git a/llvm/test/Transforms/InstSimplify/past-the-end.ll b/llvm/test/Transforms/InstSimplify/past-the-end.ll new file mode 100644 index 00000000000..b47db7defcb --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/past-the-end.ll @@ -0,0 +1,93 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s +target datalayout = "p:32:32" + +; Check some past-the-end subtleties. + +@opte_a = global i32 0 +@opte_b = global i32 0 + +; Comparing base addresses of two distinct globals. Never equal. + +define zeroext i1 @no_offsets() { +; CHECK-LABEL: @no_offsets( +; CHECK: ret i1 false +; + %t = icmp eq i32* @opte_a, @opte_b + ret i1 %t +} + +; Comparing past-the-end addresses of two distinct globals. Never equal. + +define zeroext i1 @both_past_the_end() { +; CHECK-LABEL: @both_past_the_end( +; CHECK: ret i1 icmp eq (i32* getelementptr inbounds (i32, i32* @opte_a, i32 1), i32* getelementptr inbounds (i32, i32* @opte_b, i32 1)) +; + %x = getelementptr i32, i32* @opte_a, i32 1 + %y = getelementptr i32, i32* @opte_b, i32 1 + %t = icmp eq i32* %x, %y + ret i1 %t + ; TODO: refine this +} + +; Comparing past-the-end addresses of one global to the base address +; of another. Can't fold this. + +define zeroext i1 @just_one_past_the_end() { +; CHECK-LABEL: @just_one_past_the_end( +; CHECK: ret i1 icmp eq (i32* getelementptr inbounds (i32, i32* @opte_a, i32 1), i32* @opte_b) +; + %x = getelementptr i32, i32* @opte_a, i32 1 + %t = icmp eq i32* %x, @opte_b + ret i1 %t +} + +; Comparing base addresses of two distinct allocas. Never equal. + +define zeroext i1 @no_alloca_offsets() { +; CHECK-LABEL: @no_alloca_offsets( +; CHECK: ret i1 false +; + %m = alloca i32 + %n = alloca i32 + %t = icmp eq i32* %m, %n + ret i1 %t +} + +; Comparing past-the-end addresses of two distinct allocas. Never equal. + +define zeroext i1 @both_past_the_end_alloca() { +; CHECK-LABEL: @both_past_the_end_alloca( +; CHECK: [[M:%.*]] = alloca i32 +; CHECK-NEXT: [[N:%.*]] = alloca i32 +; CHECK-NEXT: [[X:%.*]] = getelementptr i32, i32* [[M]], i32 1 +; CHECK-NEXT: [[Y:%.*]] = getelementptr i32, i32* [[N]], i32 1 +; CHECK-NEXT: [[T:%.*]] = icmp eq i32* [[X]], [[Y]] +; CHECK-NEXT: ret i1 [[T]] +; + %m = alloca i32 + %n = alloca i32 + %x = getelementptr i32, i32* %m, i32 1 + %y = getelementptr i32, i32* %n, i32 1 + %t = icmp eq i32* %x, %y + ret i1 %t + ; TODO: refine this +} + +; Comparing past-the-end addresses of one alloca to the base address +; of another. Can't fold this. + +define zeroext i1 @just_one_past_the_end_alloca() { +; CHECK-LABEL: @just_one_past_the_end_alloca( +; CHECK: [[M:%.*]] = alloca i32 +; CHECK-NEXT: [[N:%.*]] = alloca i32 +; CHECK-NEXT: [[X:%.*]] = getelementptr i32, i32* [[M]], i32 1 +; CHECK-NEXT: [[T:%.*]] = icmp eq i32* [[X]], [[N]] +; CHECK-NEXT: ret i1 [[T]] +; + %m = alloca i32 + %n = alloca i32 + %x = getelementptr i32, i32* %m, i32 1 + %t = icmp eq i32* %x, %n + ret i1 %t +} diff --git a/llvm/test/Transforms/InstSimplify/phi.ll b/llvm/test/Transforms/InstSimplify/phi.ll new file mode 100644 index 00000000000..b0040ffeb03 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/phi.ll @@ -0,0 +1,24 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; PR12189 +define i1 @test1(i32 %x) { +; CHECK-LABEL: @test1( +; CHECK: ret i1 %e +; + br i1 true, label %a, label %b + +a: + %aa = or i32 %x, 10 + br label %c + +b: + %bb = or i32 %x, 10 + br label %c + +c: + %cc = phi i32 [ %bb, %b ], [%aa, %a ] + %d = urem i32 %cc, 2 + %e = icmp eq i32 %d, 0 + ret i1 %e +} diff --git a/llvm/test/Transforms/InstSimplify/pr28725.ll b/llvm/test/Transforms/InstSimplify/pr28725.ll new file mode 100644 index 00000000000..7ff0b90c65d --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/pr28725.ll @@ -0,0 +1,12 @@ +; RUN: opt -S -instsimplify < %s | FileCheck %s +%S = type { i16, i32 } + +define <2 x i16> @test1() { +entry: + %b = insertelement <2 x i16> <i16 undef, i16 0>, i16 extractvalue (%S select (i1 icmp eq (i16 extractelement (<2 x i16> bitcast (<1 x i32> <i32 1> to <2 x i16>), i32 0), i16 0), %S zeroinitializer, %S { i16 0, i32 1 }), 0), i32 0 + ret <2 x i16> %b +} + +; InstCombine will be able to fold this into zeroinitializer +; CHECK-LABEL: @test1( +; CHECK: ret <2 x i16> <i16 extractvalue (%S select (i1 icmp eq (i16 extractelement (<2 x i16> bitcast (<1 x i32> <i32 1> to <2 x i16>), i32 0), i16 0), %S zeroinitializer, %S { i16 0, i32 1 }), 0), i16 0> diff --git a/llvm/test/Transforms/InstSimplify/pr33957.ll b/llvm/test/Transforms/InstSimplify/pr33957.ll new file mode 100644 index 00000000000..256bb89e786 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/pr33957.ll @@ -0,0 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -loop-unroll -S %s | FileCheck %s + +%struct.bar = type { i32 } + +@global = external constant [78 x %struct.bar], align 4 + +define void @patatino(i32 %x) { +; CHECK-LABEL: @patatino( +; CHECK-NEXT: bb: +; CHECK-NEXT: br i1 true, label [[BB1_PREHEADER:%.*]], label [[BB3:%.*]] +; CHECK: bb1.preheader: +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; +bb: + br i1 true, label %bb1, label %bb3 + +bb1: + %tmp = getelementptr inbounds [78 x %struct.bar], [78 x %struct.bar]* @global, i32 0, <4 x i32> undef + %tmp2 = getelementptr inbounds %struct.bar, <4 x %struct.bar*> %tmp, i32 1 + br i1 true, label %bb3, label %bb1 + +bb3: + ret void +} diff --git a/llvm/test/Transforms/InstSimplify/ptr_diff.ll b/llvm/test/Transforms/InstSimplify/ptr_diff.ll new file mode 100644 index 00000000000..c57fab99786 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/ptr_diff.ll @@ -0,0 +1,84 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i64 @ptrdiff1(i8* %ptr) { +; CHECK-LABEL: @ptrdiff1( +; CHECK: ret i64 42 +; + %first = getelementptr inbounds i8, i8* %ptr, i32 0 + %last = getelementptr inbounds i8, i8* %ptr, i32 42 + %first.int = ptrtoint i8* %first to i64 + %last.int = ptrtoint i8* %last to i64 + %diff = sub i64 %last.int, %first.int + ret i64 %diff +} + +define i64 @ptrdiff2(i8* %ptr) { +; CHECK-LABEL: @ptrdiff2( +; CHECK: ret i64 42 +; + %first1 = getelementptr inbounds i8, i8* %ptr, i32 0 + %first2 = getelementptr inbounds i8, i8* %first1, i32 1 + %first3 = getelementptr inbounds i8, i8* %first2, i32 2 + %first4 = getelementptr inbounds i8, i8* %first3, i32 4 + %last1 = getelementptr inbounds i8, i8* %first2, i32 48 + %last2 = getelementptr inbounds i8, i8* %last1, i32 8 + %last3 = getelementptr inbounds i8, i8* %last2, i32 -4 + %last4 = getelementptr inbounds i8, i8* %last3, i32 -4 + %first.int = ptrtoint i8* %first4 to i64 + %last.int = ptrtoint i8* %last4 to i64 + %diff = sub i64 %last.int, %first.int + ret i64 %diff +} + +define i64 @ptrdiff3(i8* %ptr) { +; Don't bother with non-inbounds GEPs. +; CHECK-LABEL: @ptrdiff3( +; CHECK: [[LAST:%.*]] = getelementptr i8, i8* %ptr, i32 42 +; CHECK-NEXT: [[FIRST_INT:%.*]] = ptrtoint i8* %ptr to i64 +; CHECK-NEXT: [[LAST_INT:%.*]] = ptrtoint i8* [[LAST]] to i64 +; CHECK-NEXT: [[DIFF:%.*]] = sub i64 [[LAST_INT]], [[FIRST_INT]] +; CHECK-NEXT: ret i64 [[DIFF]] +; + %first = getelementptr i8, i8* %ptr, i32 0 + %last = getelementptr i8, i8* %ptr, i32 42 + %first.int = ptrtoint i8* %first to i64 + %last.int = ptrtoint i8* %last to i64 + %diff = sub i64 %last.int, %first.int + ret i64 %diff +} + +define <4 x i32> @ptrdiff4(<4 x i8*> %arg) nounwind { +; Handle simple cases of vectors of pointers. +; CHECK-LABEL: @ptrdiff4( +; CHECK: ret <4 x i32> zeroinitializer +; + %p1 = ptrtoint <4 x i8*> %arg to <4 x i32> + %bc = bitcast <4 x i8*> %arg to <4 x i32*> + %p2 = ptrtoint <4 x i32*> %bc to <4 x i32> + %sub = sub <4 x i32> %p1, %p2 + ret <4 x i32> %sub +} + +%struct.ham = type { i32, [2 x [2 x i32]] } + +@global = internal global %struct.ham zeroinitializer, align 4 + +define i32 @ptrdiff5() nounwind { +; CHECK-LABEL: @ptrdiff5( +; CHECK: bb: +; CHECK-NEXT: ret i32 0 +; +bb: + %tmp = getelementptr inbounds %struct.ham, %struct.ham* @global, i32 0, i32 1 + %tmp1 = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %tmp, i32 0, i32 0 + %tmp2 = bitcast [2 x i32]* %tmp1 to i32* + %tmp3 = ptrtoint i32* %tmp2 to i32 + %tmp4 = getelementptr inbounds %struct.ham, %struct.ham* @global, i32 0, i32 1 + %tmp5 = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %tmp4, i32 0, i32 0 + %tmp6 = ptrtoint [2 x i32]* %tmp5 to i32 + %tmp7 = sub i32 %tmp3, %tmp6 + ret i32 %tmp7 +} diff --git a/llvm/test/Transforms/InstSimplify/reassociate.ll b/llvm/test/Transforms/InstSimplify/reassociate.ll new file mode 100644 index 00000000000..b5994e4531a --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/reassociate.ll @@ -0,0 +1,266 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @add1(i32 %x) { +; CHECK-LABEL: @add1( +; CHECK-NEXT: ret i32 [[X:%.*]] +; +; (X + -1) + 1 -> X + %l = add i32 %x, -1 + %r = add i32 %l, 1 + ret i32 %r +} + +define i32 @and1(i32 %x, i32 %y) { +; CHECK-LABEL: @and1( +; CHECK-NEXT: [[L:%.*]] = and i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[L]] +; +; (X & Y) & X -> X & Y + %l = and i32 %x, %y + %r = and i32 %l, %x + ret i32 %r +} + +define i32 @and2(i32 %x, i32 %y) { +; CHECK-LABEL: @and2( +; CHECK-NEXT: [[R:%.*]] = and i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; +; X & (X & Y) -> X & Y + %r = and i32 %x, %y + %l = and i32 %x, %r + ret i32 %l +} + +define i32 @or1(i32 %x, i32 %y) { +; CHECK-LABEL: @or1( +; CHECK-NEXT: [[L:%.*]] = or i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[L]] +; +; (X | Y) | X -> X | Y + %l = or i32 %x, %y + %r = or i32 %l, %x + ret i32 %r +} + +define i32 @or2(i32 %x, i32 %y) { +; CHECK-LABEL: @or2( +; CHECK-NEXT: [[R:%.*]] = or i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[R]] +; +; X | (X | Y) -> X | Y + %r = or i32 %x, %y + %l = or i32 %x, %r + ret i32 %l +} + +define i32 @xor1(i32 %x, i32 %y) { +; CHECK-LABEL: @xor1( +; CHECK-NEXT: ret i32 [[Y:%.*]] +; +; (X ^ Y) ^ X = Y + %l = xor i32 %x, %y + %r = xor i32 %l, %x + ret i32 %r +} + +define i32 @xor2(i32 %x, i32 %y) { +; CHECK-LABEL: @xor2( +; CHECK-NEXT: ret i32 [[Y:%.*]] +; +; X ^ (X ^ Y) = Y + %r = xor i32 %x, %y + %l = xor i32 %x, %r + ret i32 %l +} + +define i32 @sub1(i32 %x, i32 %y) { +; CHECK-LABEL: @sub1( +; CHECK-NEXT: ret i32 [[Y:%.*]] +; + %d = sub i32 %x, %y + %r = sub i32 %x, %d + ret i32 %r +} + +define i32 @sub2(i32 %x) { +; CHECK-LABEL: @sub2( +; CHECK-NEXT: ret i32 -1 +; +; X - (X + 1) -> -1 + %xp1 = add i32 %x, 1 + %r = sub i32 %x, %xp1 + ret i32 %r +} + +define i32 @sub3(i32 %x, i32 %y) { +; CHECK-LABEL: @sub3( +; CHECK-NEXT: ret i32 [[X:%.*]] +; +; ((X + 1) + Y) - (Y + 1) -> X + %xp1 = add i32 %x, 1 + %lhs = add i32 %xp1, %y + %rhs = add i32 %y, 1 + %r = sub i32 %lhs, %rhs + ret i32 %r +} + +; (no overflow X * Y) / Y -> X + +define i32 @mulnsw_sdiv(i32 %x, i32 %y) { +; CHECK-LABEL: @mulnsw_sdiv( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %mul = mul nsw i32 %x, %y + %r = sdiv i32 %mul, %y + ret i32 %r +} + +define <2 x i32> @mulnsw_sdiv_commute(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @mulnsw_sdiv_commute( +; CHECK-NEXT: ret <2 x i32> [[X:%.*]] +; + %mul = mul nsw <2 x i32> %y, %x + %r = sdiv <2 x i32> %mul, %y + ret <2 x i32> %r +} + +; (no overflow X * Y) / Y -> X + +define <2 x i8> @mulnuw_udiv(<2 x i8> %x, <2 x i8> %y) { +; CHECK-LABEL: @mulnuw_udiv( +; CHECK-NEXT: ret <2 x i8> [[X:%.*]] +; + %mul = mul nuw <2 x i8> %x, %y + %r = udiv <2 x i8> %mul, %y + ret <2 x i8> %r +} + +define i32 @mulnuw_udiv_commute(i32 %x, i32 %y) { +; CHECK-LABEL: @mulnuw_udiv_commute( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %mul = mul nuw i32 %y, %x + %r = udiv i32 %mul, %y + ret i32 %r +} + +; (((X / Y) * Y) / Y) -> X / Y + +define i32 @sdiv_mul_sdiv(i32 %x, i32 %y) { +; CHECK-LABEL: @sdiv_mul_sdiv( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %div = sdiv i32 %x, %y + %mul = mul i32 %div, %y + %r = sdiv i32 %mul, %y + ret i32 %r +} + +define i32 @sdiv_mul_sdiv_commute(i32 %x, i32 %y) { +; CHECK-LABEL: @sdiv_mul_sdiv_commute( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %div = sdiv i32 %x, %y + %mul = mul i32 %y, %div + %r = sdiv i32 %mul, %y + ret i32 %r +} + +; (((X / Y) * Y) / Y) -> X / Y + +define i32 @udiv_mul_udiv(i32 %x, i32 %y) { +; CHECK-LABEL: @udiv_mul_udiv( +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %div = udiv i32 %x, %y + %mul = mul i32 %div, %y + %r = udiv i32 %mul, %y + ret i32 %r +} + +define i32 @udiv_mul_udiv_commute(i32 %x, i32 %y) { +; CHECK-LABEL: @udiv_mul_udiv_commute( +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %div = udiv i32 %x, %y + %mul = mul i32 %y, %div + %r = udiv i32 %mul, %y + ret i32 %r +} + +define i32 @sdiv3(i32 %x, i32 %y) { +; CHECK-LABEL: @sdiv3( +; CHECK-NEXT: ret i32 0 +; +; (X rem Y) / Y -> 0 + %rem = srem i32 %x, %y + %div = sdiv i32 %rem, %y + ret i32 %div +} + +define i32 @sdiv4(i32 %x, i32 %y) { +; CHECK-LABEL: @sdiv4( +; CHECK-NEXT: ret i32 [[X:%.*]] +; +; (X / Y) * Y -> X if the division is exact + %div = sdiv exact i32 %x, %y + %mul = mul i32 %div, %y + ret i32 %mul +} + +define i32 @sdiv5(i32 %x, i32 %y) { +; CHECK-LABEL: @sdiv5( +; CHECK-NEXT: ret i32 [[X:%.*]] +; +; Y * (X / Y) -> X if the division is exact + %div = sdiv exact i32 %x, %y + %mul = mul i32 %y, %div + ret i32 %mul +} + +define i32 @udiv3(i32 %x, i32 %y) { +; CHECK-LABEL: @udiv3( +; CHECK-NEXT: ret i32 0 +; +; (X rem Y) / Y -> 0 + %rem = urem i32 %x, %y + %div = udiv i32 %rem, %y + ret i32 %div +} + +define i32 @udiv4(i32 %x, i32 %y) { +; CHECK-LABEL: @udiv4( +; CHECK-NEXT: ret i32 [[X:%.*]] +; +; (X / Y) * Y -> X if the division is exact + %div = udiv exact i32 %x, %y + %mul = mul i32 %div, %y + ret i32 %mul +} + +define i32 @udiv5(i32 %x, i32 %y) { +; CHECK-LABEL: @udiv5( +; CHECK-NEXT: ret i32 [[X:%.*]] +; +; Y * (X / Y) -> X if the division is exact + %div = udiv exact i32 %x, %y + %mul = mul i32 %y, %div + ret i32 %mul +} + +define i16 @trunc1(i32 %x) { +; CHECK-LABEL: @trunc1( +; CHECK-NEXT: ret i16 1 +; + %y = add i32 %x, 1 + %tx = trunc i32 %x to i16 + %ty = trunc i32 %y to i16 + %d = sub i16 %ty, %tx + ret i16 %d +} diff --git a/llvm/test/Transforms/InstSimplify/rem.ll b/llvm/test/Transforms/InstSimplify/rem.ll new file mode 100644 index 00000000000..e18ff567414 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/rem.ll @@ -0,0 +1,327 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @zero_dividend(i32 %A) { +; CHECK-LABEL: @zero_dividend( +; CHECK-NEXT: ret i32 0 +; + %B = urem i32 0, %A + ret i32 %B +} + +define <2 x i32> @zero_dividend_vector(<2 x i32> %A) { +; CHECK-LABEL: @zero_dividend_vector( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %B = srem <2 x i32> zeroinitializer, %A + ret <2 x i32> %B +} + +define <2 x i32> @zero_dividend_vector_undef_elt(<2 x i32> %A) { +; CHECK-LABEL: @zero_dividend_vector_undef_elt( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %B = urem <2 x i32> <i32 undef, i32 0>, %A + ret <2 x i32> %B +} + +; Division-by-zero is undef. UB in any vector lane means the whole op is undef. + +define <2 x i8> @srem_zero_elt_vec_constfold(<2 x i8> %x) { +; CHECK-LABEL: @srem_zero_elt_vec_constfold( +; CHECK-NEXT: ret <2 x i8> undef +; + %rem = srem <2 x i8> <i8 1, i8 2>, <i8 0, i8 -42> + ret <2 x i8> %rem +} + +define <2 x i8> @urem_zero_elt_vec_constfold(<2 x i8> %x) { +; CHECK-LABEL: @urem_zero_elt_vec_constfold( +; CHECK-NEXT: ret <2 x i8> undef +; + %rem = urem <2 x i8> <i8 1, i8 2>, <i8 42, i8 0> + ret <2 x i8> %rem +} + +define <2 x i8> @srem_zero_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @srem_zero_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %rem = srem <2 x i8> %x, <i8 -42, i8 0> + ret <2 x i8> %rem +} + +define <2 x i8> @urem_zero_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @urem_zero_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %rem = urem <2 x i8> %x, <i8 0, i8 42> + ret <2 x i8> %rem +} + +define <2 x i8> @srem_undef_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @srem_undef_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %rem = srem <2 x i8> %x, <i8 -42, i8 undef> + ret <2 x i8> %rem +} + +define <2 x i8> @urem_undef_elt_vec(<2 x i8> %x) { +; CHECK-LABEL: @urem_undef_elt_vec( +; CHECK-NEXT: ret <2 x i8> undef +; + %rem = urem <2 x i8> %x, <i8 undef, i8 42> + ret <2 x i8> %rem +} + +; Division-by-zero is undef. UB in any vector lane means the whole op is undef. +; Thus, we can simplify this: if any element of 'y' is 0, we can do anything. +; Therefore, assume that all elements of 'y' must be 1. + +define <2 x i1> @srem_bool_vec(<2 x i1> %x, <2 x i1> %y) { +; CHECK-LABEL: @srem_bool_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %rem = srem <2 x i1> %x, %y + ret <2 x i1> %rem +} + +define <2 x i1> @urem_bool_vec(<2 x i1> %x, <2 x i1> %y) { +; CHECK-LABEL: @urem_bool_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %rem = urem <2 x i1> %x, %y + ret <2 x i1> %rem +} + +define <2 x i32> @zext_bool_urem_divisor_vec(<2 x i1> %x, <2 x i32> %y) { +; CHECK-LABEL: @zext_bool_urem_divisor_vec( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %ext = zext <2 x i1> %x to <2 x i32> + %r = urem <2 x i32> %y, %ext + ret <2 x i32> %r +} + +define i32 @zext_bool_srem_divisor(i1 %x, i32 %y) { +; CHECK-LABEL: @zext_bool_srem_divisor( +; CHECK-NEXT: ret i32 0 +; + %ext = zext i1 %x to i32 + %r = srem i32 %y, %ext + ret i32 %r +} + +define i32 @select1(i32 %x, i1 %b) { +; CHECK-LABEL: @select1( +; CHECK-NEXT: ret i32 0 +; + %rhs = select i1 %b, i32 %x, i32 1 + %rem = srem i32 %x, %rhs + ret i32 %rem +} + +define i32 @select2(i32 %x, i1 %b) { +; CHECK-LABEL: @select2( +; CHECK-NEXT: ret i32 0 +; + %rhs = select i1 %b, i32 %x, i32 1 + %rem = urem i32 %x, %rhs + ret i32 %rem +} + +define i32 @rem1(i32 %x, i32 %n) { +; CHECK-LABEL: @rem1( +; CHECK-NEXT: [[MOD:%.*]] = srem i32 [[X:%.*]], [[N:%.*]] +; CHECK-NEXT: ret i32 [[MOD]] +; + %mod = srem i32 %x, %n + %mod1 = srem i32 %mod, %n + ret i32 %mod1 +} + +define i32 @rem2(i32 %x, i32 %n) { +; CHECK-LABEL: @rem2( +; CHECK-NEXT: [[MOD:%.*]] = urem i32 [[X:%.*]], [[N:%.*]] +; CHECK-NEXT: ret i32 [[MOD]] +; + %mod = urem i32 %x, %n + %mod1 = urem i32 %mod, %n + ret i32 %mod1 +} + +define i32 @rem3(i32 %x, i32 %n) { +; CHECK-LABEL: @rem3( +; CHECK-NEXT: [[MOD:%.*]] = srem i32 [[X:%.*]], [[N:%.*]] +; CHECK-NEXT: [[MOD1:%.*]] = urem i32 [[MOD]], [[N]] +; CHECK-NEXT: ret i32 [[MOD1]] +; + %mod = srem i32 %x, %n + %mod1 = urem i32 %mod, %n + ret i32 %mod1 +} + +define i32 @urem_dividend_known_smaller_than_constant_divisor(i32 %x) { +; CHECK-LABEL: @urem_dividend_known_smaller_than_constant_divisor( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 250 +; CHECK-NEXT: ret i32 [[AND]] +; + %and = and i32 %x, 250 + %r = urem i32 %and, 251 + ret i32 %r +} + +define i32 @not_urem_dividend_known_smaller_than_constant_divisor(i32 %x) { +; CHECK-LABEL: @not_urem_dividend_known_smaller_than_constant_divisor( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 251 +; CHECK-NEXT: [[R:%.*]] = urem i32 [[AND]], 251 +; CHECK-NEXT: ret i32 [[R]] +; + %and = and i32 %x, 251 + %r = urem i32 %and, 251 + ret i32 %r +} + +define i32 @urem_constant_dividend_known_smaller_than_divisor(i32 %x) { +; CHECK-LABEL: @urem_constant_dividend_known_smaller_than_divisor( +; CHECK-NEXT: ret i32 250 +; + %or = or i32 %x, 251 + %r = urem i32 250, %or + ret i32 %r +} + +define i32 @not_urem_constant_dividend_known_smaller_than_divisor(i32 %x) { +; CHECK-LABEL: @not_urem_constant_dividend_known_smaller_than_divisor( +; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 251 +; CHECK-NEXT: [[R:%.*]] = urem i32 251, [[OR]] +; CHECK-NEXT: ret i32 [[R]] +; + %or = or i32 %x, 251 + %r = urem i32 251, %or + ret i32 %r +} + +; This would require computing known bits on both x and y. Is it worth doing? + +define i32 @urem_dividend_known_smaller_than_divisor(i32 %x, i32 %y) { +; CHECK-LABEL: @urem_dividend_known_smaller_than_divisor( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 250 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 251 +; CHECK-NEXT: [[R:%.*]] = urem i32 [[AND]], [[OR]] +; CHECK-NEXT: ret i32 [[R]] +; + %and = and i32 %x, 250 + %or = or i32 %y, 251 + %r = urem i32 %and, %or + ret i32 %r +} + +define i32 @not_urem_dividend_known_smaller_than_divisor(i32 %x, i32 %y) { +; CHECK-LABEL: @not_urem_dividend_known_smaller_than_divisor( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 251 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 251 +; CHECK-NEXT: [[R:%.*]] = urem i32 [[AND]], [[OR]] +; CHECK-NEXT: ret i32 [[R]] +; + %and = and i32 %x, 251 + %or = or i32 %y, 251 + %r = urem i32 %and, %or + ret i32 %r +} + +declare i32 @external() + +define i32 @rem4() { +; CHECK-LABEL: @rem4( +; CHECK-NEXT: [[CALL:%.*]] = call i32 @external(), !range !0 +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = call i32 @external(), !range !0 + %urem = urem i32 %call, 3 + ret i32 %urem +} + +!0 = !{i32 0, i32 3} + +define i32 @rem5(i32 %x, i32 %y) { +; CHECK-LABEL: @rem5( +; CHECK-NEXT: ret i32 0 +; + %shl = shl nsw i32 %x, %y + %mod = srem i32 %shl, %x + ret i32 %mod +} + +define <2 x i32> @rem6(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @rem6( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %shl = shl nsw <2 x i32> %x, %y + %mod = srem <2 x i32> %shl, %x + ret <2 x i32> %mod +} + +; make sure the previous fold doesn't take place for wrapped shifts + +define i32 @rem7(i32 %x, i32 %y) { +; CHECK-LABEL: @rem7( +; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[MOD:%.*]] = srem i32 [[SHL]], [[X]] +; CHECK-NEXT: ret i32 [[MOD]] +; + %shl = shl i32 %x, %y + %mod = srem i32 %shl, %x + ret i32 %mod +} + +define i32 @rem8(i32 %x, i32 %y) { +; CHECK-LABEL: @rem8( +; CHECK-NEXT: ret i32 0 +; + %shl = shl nuw i32 %x, %y + %mod = urem i32 %shl, %x + ret i32 %mod +} + +define <2 x i32> @rem9(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @rem9( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %shl = shl nuw <2 x i32> %x, %y + %mod = urem <2 x i32> %shl, %x + ret <2 x i32> %mod +} + +; make sure the previous fold doesn't take place for wrapped shifts + +define i32 @rem10(i32 %x, i32 %y) { +; CHECK-LABEL: @rem10( +; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[MOD:%.*]] = urem i32 [[SHL]], [[X]] +; CHECK-NEXT: ret i32 [[MOD]] +; + %shl = shl i32 %x, %y + %mod = urem i32 %shl, %x + ret i32 %mod +} + +define i32 @srem_with_sext_bool_divisor(i1 %x, i32 %y) { +; CHECK-LABEL: @srem_with_sext_bool_divisor( +; CHECK-NEXT: ret i32 0 +; + %s = sext i1 %x to i32 + %r = srem i32 %y, %s + ret i32 %r +} + +define <2 x i32> @srem_with_sext_bool_divisor_vec(<2 x i1> %x, <2 x i32> %y) { +; CHECK-LABEL: @srem_with_sext_bool_divisor_vec( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %s = sext <2 x i1> %x to <2 x i32> + %r = srem <2 x i32> %y, %s + ret <2 x i32> %r +} + diff --git a/llvm/test/Transforms/InstSimplify/require-dominator.ll b/llvm/test/Transforms/InstSimplify/require-dominator.ll new file mode 100644 index 00000000000..ce24cc8a1de --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/require-dominator.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -instsimplify + +; instsimplify pass should explicitly require DominatorTreeAnalysis +; This test will segfault if DominatorTree is not available + +target triple = "x86_64-grtev4-linux-gnu" + +; Function Attrs: nounwind uwtable +define void @foo(i16 *) #1 align 2 { + br i1 undef, label %exit, label %2 + +; <label>:2: + %3 = tail call i8* @_Znwm(i64 56) #10 + %4 = bitcast i8* %3 to i16* + %p = load i16*, i16** undef, align 8 + %5 = icmp eq i16* %p, %4 + br i1 %5, label %exit, label %6 + +; <label>:6: + %7 = icmp eq i16* %p, null + br i1 %7, label %exit, label %8 + +; <label>:8: + br label %exit + +exit: + ret void +} + +; Function Attrs: nobuiltin +declare i8* @_Znwm(i64) diff --git a/llvm/test/Transforms/InstSimplify/returned.ll b/llvm/test/Transforms/InstSimplify/returned.ll new file mode 100644 index 00000000000..0e89e91085d --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/returned.ll @@ -0,0 +1,30 @@ +; RUN: opt -instsimplify -S < %s | FileCheck %s + +define i1 @bitcast() { +; CHECK-LABEL: @bitcast( + %a = alloca i32 + %b = alloca i64 + %x = bitcast i32* %a to i8* + %z = bitcast i64* %b to i8* + %y = call i8* @func1(i8* %z) + %cmp = icmp eq i8* %x, %y + ret i1 %cmp +; CHECK-NEXT: ret i1 false +} + +%gept = type { i32, i32 } + +define i1 @gep3() { +; CHECK-LABEL: @gep3( + %x = alloca %gept, align 8 + %a = getelementptr %gept, %gept* %x, i64 0, i32 0 + %y = call %gept* @func2(%gept* %x) + %b = getelementptr %gept, %gept* %y, i64 0, i32 1 + %equal = icmp eq i32* %a, %b + ret i1 %equal +; CHECK-NEXT: ret i1 false +} + +declare i8* @func1(i8* returned) nounwind readnone +declare %gept* @func2(%gept* returned) nounwind readnone + diff --git a/llvm/test/Transforms/InstSimplify/round-intrinsics.ll b/llvm/test/Transforms/InstSimplify/round-intrinsics.ll new file mode 100644 index 00000000000..42c78e000ac --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/round-intrinsics.ll @@ -0,0 +1,131 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instsimplify %s | FileCheck %s + +define float @sitofp_floor(i32 %arg) { +; CHECK-LABEL: @sitofp_floor( +; CHECK-NEXT: [[CVT:%.*]] = sitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = sitofp i32 %arg to float + %round = call float @llvm.floor.f32(float %cvt) + ret float %round +} + +define float @uitofp_floor(i32 %arg) { +; CHECK-LABEL: @uitofp_floor( +; CHECK-NEXT: [[CVT:%.*]] = uitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = uitofp i32 %arg to float + %round = call float @llvm.floor.f32(float %cvt) + ret float %round +} + +define float @sitofp_trunc(i32 %arg) { +; CHECK-LABEL: @sitofp_trunc( +; CHECK-NEXT: [[CVT:%.*]] = sitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = sitofp i32 %arg to float + %round = call float @llvm.trunc.f32(float %cvt) + ret float %round +} + +define float @uitofp_trunc(i32 %arg) { +; CHECK-LABEL: @uitofp_trunc( +; CHECK-NEXT: [[CVT:%.*]] = uitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = uitofp i32 %arg to float + %round = call float @llvm.trunc.f32(float %cvt) + ret float %round +} + +define float @sitofp_ceil(i32 %arg) { +; CHECK-LABEL: @sitofp_ceil( +; CHECK-NEXT: [[CVT:%.*]] = sitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = sitofp i32 %arg to float + %round = call float @llvm.ceil.f32(float %cvt) + ret float %round +} + +define float @uitofp_ceil(i32 %arg) { +; CHECK-LABEL: @uitofp_ceil( +; CHECK-NEXT: [[CVT:%.*]] = uitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = uitofp i32 %arg to float + %round = call float @llvm.ceil.f32(float %cvt) + ret float %round +} + +define float @sitofp_round(i32 %arg) { +; CHECK-LABEL: @sitofp_round( +; CHECK-NEXT: [[CVT:%.*]] = sitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = sitofp i32 %arg to float + %round = call float @llvm.round.f32(float %cvt) + ret float %round +} + +define float @uitofp_round(i32 %arg) { +; CHECK-LABEL: @uitofp_round( +; CHECK-NEXT: [[CVT:%.*]] = uitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = uitofp i32 %arg to float + %round = call float @llvm.round.f32(float %cvt) + ret float %round +} + +define float @sitofp_nearbyint(i32 %arg) { +; CHECK-LABEL: @sitofp_nearbyint( +; CHECK-NEXT: [[CVT:%.*]] = sitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = sitofp i32 %arg to float + %nearbyint = call float @llvm.nearbyint.f32(float %cvt) + ret float %nearbyint +} + +define float @uitofp_nearbyint(i32 %arg) { +; CHECK-LABEL: @uitofp_nearbyint( +; CHECK-NEXT: [[CVT:%.*]] = uitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = uitofp i32 %arg to float + %nearbyint = call float @llvm.nearbyint.f32(float %cvt) + ret float %nearbyint +} + +define float @sitofp_rint(i32 %arg) { +; CHECK-LABEL: @sitofp_rint( +; CHECK-NEXT: [[CVT:%.*]] = sitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = sitofp i32 %arg to float + %rint = call float @llvm.rint.f32(float %cvt) + ret float %rint +} + +define float @uitofp_rint(i32 %arg) { +; CHECK-LABEL: @uitofp_rint( +; CHECK-NEXT: [[CVT:%.*]] = uitofp i32 [[ARG:%.*]] to float +; CHECK-NEXT: ret float [[CVT]] +; + %cvt = uitofp i32 %arg to float + %rint = call float @llvm.rint.f32(float %cvt) + ret float %rint +} + +declare float @llvm.floor.f32(float) #0 +declare float @llvm.trunc.f32(float) #0 +declare float @llvm.ceil.f32(float) #0 +declare float @llvm.round.f32(float) #0 +declare float @llvm.nearbyint.f32(float) #0 +declare float @llvm.rint.f32(float) #0 + +attributes #0 = { nounwind readnone speculatable } diff --git a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll new file mode 100644 index 00000000000..a226cc456ac --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll @@ -0,0 +1,666 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +declare i3 @llvm.uadd.sat.i3(i3, i3) +declare i8 @llvm.uadd.sat.i8(i8, i8) +declare <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8>, <2 x i8>) +declare <2 x i9> @llvm.uadd.sat.v2i9(<2 x i9>, <2 x i9>) + +declare i8 @llvm.sadd.sat.i8(i8, i8) +declare <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8>, <2 x i8>) + +declare i8 @llvm.usub.sat.i8(i8, i8) +declare i8 @llvm.ssub.sat.i8(i8, i8) +declare <2 x i8> @llvm.usub.sat.v2i8(<2 x i8>, <2 x i8>) +declare <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8>, <2 x i8>) + +define i8 @uadd_scalar_0(i8 %a) { +; CHECK-LABEL: @uadd_scalar_0( +; CHECK-NEXT: ret i8 [[A:%.*]] +; + %x1 = call i8 @llvm.uadd.sat.i8(i8 %a, i8 0) + ret i8 %x1 +} + +define <2 x i8> @uadd_vector_0(<2 x i8> %a) { +; CHECK-LABEL: @uadd_vector_0( +; CHECK-NEXT: ret <2 x i8> [[A:%.*]] +; + %x1v = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %a, <2 x i8> zeroinitializer) + ret <2 x i8> %x1v +} + +define i3 @uadd_scalar_0_commute(i3 %a) { +; CHECK-LABEL: @uadd_scalar_0_commute( +; CHECK-NEXT: ret i3 [[A:%.*]] +; + %x2 = call i3 @llvm.uadd.sat.i3(i3 0, i3 %a) + ret i3 %x2 +} + +define <2 x i8> @uadd_vector_0_commute(<2 x i8> %a) { +; CHECK-LABEL: @uadd_vector_0_commute( +; CHECK-NEXT: ret <2 x i8> [[A:%.*]] +; + %x2v = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> <i8 0, i8 undef>, <2 x i8> %a) + ret <2 x i8> %x2v +} + +define i8 @uadd_scalar_maxval(i8 %a) { +; CHECK-LABEL: @uadd_scalar_maxval( +; CHECK-NEXT: ret i8 -1 +; + %x3 = call i8 @llvm.uadd.sat.i8(i8 %a, i8 255) + ret i8 %x3 +} + +define <2 x i9> @uadd_vector_maxval(<2 x i9> %a) { +; CHECK-LABEL: @uadd_vector_maxval( +; CHECK-NEXT: ret <2 x i9> <i9 -1, i9 -1> +; + %x3v = call <2 x i9> @llvm.uadd.sat.v2i9(<2 x i9> %a, <2 x i9> <i9 511, i9 511>) + ret <2 x i9> %x3v +} + +define i3 @uadd_scalar_maxval_commute(i3 %a) { +; CHECK-LABEL: @uadd_scalar_maxval_commute( +; CHECK-NEXT: ret i3 -1 +; + %x4 = call i3 @llvm.uadd.sat.i3(i3 7, i3 %a) + ret i3 %x4 +} + +define <2 x i8> @uadd_vector_maxval_commute(<2 x i8> %a) { +; CHECK-LABEL: @uadd_vector_maxval_commute( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1> +; + %x4v = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> <i8 255, i8 255>, <2 x i8> %a) + ret <2 x i8> %x4v +} + +define i8 @uadd_scalar_undef(i8 %a) { +; CHECK-LABEL: @uadd_scalar_undef( +; CHECK-NEXT: ret i8 -1 +; + %x5 = call i8 @llvm.uadd.sat.i8(i8 %a, i8 undef) + ret i8 %x5 +} + +define <2 x i8> @uadd_vector_undef(<2 x i8> %a) { +; CHECK-LABEL: @uadd_vector_undef( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1> +; + %x5v = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 undef, i8 undef>) + ret <2 x i8> %x5v +} + +define i8 @uadd_scalar_undef_commute(i8 %a) { +; CHECK-LABEL: @uadd_scalar_undef_commute( +; CHECK-NEXT: ret i8 -1 +; + %x6 = call i8 @llvm.uadd.sat.i8(i8 undef, i8 %a) + ret i8 %x6 +} + +define <2 x i8> @uadd_vector_undef_commute(<2 x i8> %a) { +; CHECK-LABEL: @uadd_vector_undef_commute( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1> +; + %x5v = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> undef, <2 x i8> %a) + ret <2 x i8> %x5v +} + +define i8 @sadd_scalar_0(i8 %a) { +; CHECK-LABEL: @sadd_scalar_0( +; CHECK-NEXT: ret i8 [[A:%.*]] +; + %y1 = call i8 @llvm.sadd.sat.i8(i8 %a, i8 0) + ret i8 %y1 +} + +define <2 x i8> @sadd_vector_0(<2 x i8> %a) { +; CHECK-LABEL: @sadd_vector_0( +; CHECK-NEXT: ret <2 x i8> [[A:%.*]] +; + %y1v = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 undef, i8 0>) + ret <2 x i8> %y1v +} + +define i8 @sadd_scalar_0_commute(i8 %a) { +; CHECK-LABEL: @sadd_scalar_0_commute( +; CHECK-NEXT: ret i8 [[A:%.*]] +; + %y2 = call i8 @llvm.sadd.sat.i8(i8 0, i8 %a) + ret i8 %y2 +} + +define <2 x i8> @sadd_vector_0_commute(<2 x i8> %a) { +; CHECK-LABEL: @sadd_vector_0_commute( +; CHECK-NEXT: ret <2 x i8> [[A:%.*]] +; + %y2v = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> zeroinitializer, <2 x i8> %a) + ret <2 x i8> %y2v +} + +define i8 @sadd_scalar_maxval(i8 %a) { +; CHECK-LABEL: @sadd_scalar_maxval( +; CHECK-NEXT: [[Y3:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[A:%.*]], i8 127) +; CHECK-NEXT: ret i8 [[Y3]] +; + %y3 = call i8 @llvm.sadd.sat.i8(i8 %a, i8 127) + ret i8 %y3 +} + +define <2 x i8> @sadd_vector_maxval(<2 x i8> %a) { +; CHECK-LABEL: @sadd_vector_maxval( +; CHECK-NEXT: [[Y3V:%.*]] = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> <i8 127, i8 127>) +; CHECK-NEXT: ret <2 x i8> [[Y3V]] +; + %y3v = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 127, i8 127>) + ret <2 x i8> %y3v +} + +define i8 @sadd_scalar_maxval_commute(i8 %a) { +; CHECK-LABEL: @sadd_scalar_maxval_commute( +; CHECK-NEXT: [[Y4:%.*]] = call i8 @llvm.sadd.sat.i8(i8 127, i8 [[A:%.*]]) +; CHECK-NEXT: ret i8 [[Y4]] +; + %y4 = call i8 @llvm.sadd.sat.i8(i8 127, i8 %a) + ret i8 %y4 +} + +define <2 x i8> @sadd_vector_maxval_commute(<2 x i8> %a) { +; CHECK-LABEL: @sadd_vector_maxval_commute( +; CHECK-NEXT: [[Y4V:%.*]] = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> <i8 undef, i8 127>, <2 x i8> [[A:%.*]]) +; CHECK-NEXT: ret <2 x i8> [[Y4V]] +; + %y4v = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> <i8 undef, i8 127>, <2 x i8> %a) + ret <2 x i8> %y4v +} + +define i8 @sadd_scalar_undef(i8 %a) { +; CHECK-LABEL: @sadd_scalar_undef( +; CHECK-NEXT: ret i8 -1 +; + %y5 = call i8 @llvm.sadd.sat.i8(i8 %a, i8 undef) + ret i8 %y5 +} + +define <2 x i8> @sadd_vector_undef(<2 x i8> %a) { +; CHECK-LABEL: @sadd_vector_undef( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1> +; + %y5v = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %a, <2 x i8> undef) + ret <2 x i8> %y5v +} + +define i8 @sadd_scalar_undef_commute(i8 %a) { +; CHECK-LABEL: @sadd_scalar_undef_commute( +; CHECK-NEXT: ret i8 -1 +; + %y6 = call i8 @llvm.sadd.sat.i8(i8 undef, i8 %a) + ret i8 %y6 +} + +define <2 x i8> @sadd_vector_undef_commute(<2 x i8> %a) { +; CHECK-LABEL: @sadd_vector_undef_commute( +; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1> +; + %y6v = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> undef, <2 x i8> %a) + ret <2 x i8> %y6v +} + +define i8 @usub_scalar_0(i8 %a) { +; CHECK-LABEL: @usub_scalar_0( +; CHECK-NEXT: ret i8 [[A:%.*]] +; + %x1 = call i8 @llvm.usub.sat.i8(i8 %a, i8 0) + ret i8 %x1 +} + +define <2 x i8> @usub_vector_0(<2 x i8> %a) { +; CHECK-LABEL: @usub_vector_0( +; CHECK-NEXT: ret <2 x i8> [[A:%.*]] +; + %x1v = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 0, i8 0>) + ret <2 x i8> %x1v +} + +define i8 @usub_scalar_0_commute(i8 %a) { +; CHECK-LABEL: @usub_scalar_0_commute( +; CHECK-NEXT: ret i8 0 +; + %x2 = call i8 @llvm.usub.sat.i8(i8 0, i8 %a) + ret i8 %x2 +} + +define <2 x i8> @usub_vector_0_commute(<2 x i8> %a) { +; CHECK-LABEL: @usub_vector_0_commute( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %x2v = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> <i8 0, i8 0>, <2 x i8> %a) + ret <2 x i8> %x2v +} + +define i8 @usub_scalar_maxval(i8 %a) { +; CHECK-LABEL: @usub_scalar_maxval( +; CHECK-NEXT: ret i8 0 +; + %x3 = call i8 @llvm.usub.sat.i8(i8 %a, i8 255) + ret i8 %x3 +} + +define <2 x i8> @usub_vector_maxval(<2 x i8> %a) { +; CHECK-LABEL: @usub_vector_maxval( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %x3v = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 255, i8 255>) + ret <2 x i8> %x3v +} + +define i8 @usub_scalar_undef(i8 %a) { +; CHECK-LABEL: @usub_scalar_undef( +; CHECK-NEXT: ret i8 0 +; + %x4 = call i8 @llvm.usub.sat.i8(i8 %a, i8 undef) + ret i8 %x4 +} + +define <2 x i8> @usub_vector_undef(<2 x i8> %a) { +; CHECK-LABEL: @usub_vector_undef( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %x4v = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 undef, i8 undef>) + ret <2 x i8> %x4v +} + +define i8 @usub_scalar_undef_commute(i8 %a) { +; CHECK-LABEL: @usub_scalar_undef_commute( +; CHECK-NEXT: ret i8 0 +; + %x5 = call i8 @llvm.usub.sat.i8(i8 undef, i8 %a) + ret i8 %x5 +} + +define <2 x i8> @usub_vector_undef_commute(<2 x i8> %a) { +; CHECK-LABEL: @usub_vector_undef_commute( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %x5v = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> <i8 undef, i8 undef>, <2 x i8> %a) + ret <2 x i8> %x5v +} + +define i8 @usub_scalar_same(i8 %a) { +; CHECK-LABEL: @usub_scalar_same( +; CHECK-NEXT: ret i8 0 +; + %x6 = call i8 @llvm.usub.sat.i8(i8 %a, i8 %a) + ret i8 %x6 +} + +define <2 x i8> @usub_vector_same(<2 x i8> %a) { +; CHECK-LABEL: @usub_vector_same( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %x6v = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> %a) + ret <2 x i8> %x6v +} + +define i8 @ssub_scalar_0(i8 %a) { +; CHECK-LABEL: @ssub_scalar_0( +; CHECK-NEXT: ret i8 [[A:%.*]] +; + %y1 = call i8 @llvm.ssub.sat.i8(i8 %a, i8 0) + ret i8 %y1 +} + +define <2 x i8> @ssub_vector_0(<2 x i8> %a) { +; CHECK-LABEL: @ssub_vector_0( +; CHECK-NEXT: ret <2 x i8> [[A:%.*]] +; + %y1v = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 0, i8 0>) + ret <2 x i8> %y1v +} + +define i8 @ssub_scalar_0_commute(i8 %a) { +; CHECK-LABEL: @ssub_scalar_0_commute( +; CHECK-NEXT: [[Y2:%.*]] = call i8 @llvm.ssub.sat.i8(i8 0, i8 [[A:%.*]]) +; CHECK-NEXT: ret i8 [[Y2]] +; + %y2 = call i8 @llvm.ssub.sat.i8(i8 0, i8 %a) + ret i8 %y2 +} + +define <2 x i8> @ssub_vector_0_commute(<2 x i8> %a) { +; CHECK-LABEL: @ssub_vector_0_commute( +; CHECK-NEXT: [[Y2V:%.*]] = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> zeroinitializer, <2 x i8> [[A:%.*]]) +; CHECK-NEXT: ret <2 x i8> [[Y2V]] +; + %y2v = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> <i8 0, i8 0>, <2 x i8> %a) + ret <2 x i8> %y2v +} + +define i8 @ssub_scalar_maxval(i8 %a) { +; CHECK-LABEL: @ssub_scalar_maxval( +; CHECK-NEXT: [[Y3:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A:%.*]], i8 127) +; CHECK-NEXT: ret i8 [[Y3]] +; + %y3 = call i8 @llvm.ssub.sat.i8(i8 %a, i8 127) + ret i8 %y3 +} + +define <2 x i8> @ssub_vector_maxval(<2 x i8> %a) { +; CHECK-LABEL: @ssub_vector_maxval( +; CHECK-NEXT: [[Y3V:%.*]] = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> <i8 127, i8 127>) +; CHECK-NEXT: ret <2 x i8> [[Y3V]] +; + %y3v = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 127, i8 127>) + ret <2 x i8> %y3v +} + +define i8 @ssub_scalar_undef(i8 %a) { +; CHECK-LABEL: @ssub_scalar_undef( +; CHECK-NEXT: ret i8 0 +; + %y4 = call i8 @llvm.ssub.sat.i8(i8 %a, i8 undef) + ret i8 %y4 +} + +define <2 x i8> @ssub_vector_undef(<2 x i8> %a) { +; CHECK-LABEL: @ssub_vector_undef( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %y4v = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %a, <2 x i8> undef) + ret <2 x i8> %y4v +} + +define i8 @ssub_scalar_undef_commute(i8 %a) { +; CHECK-LABEL: @ssub_scalar_undef_commute( +; CHECK-NEXT: ret i8 0 +; + %y5 = call i8 @llvm.ssub.sat.i8(i8 undef, i8 %a) + ret i8 %y5 +} + +define <2 x i8> @ssub_vector_undef_commute(<2 x i8> %a) { +; CHECK-LABEL: @ssub_vector_undef_commute( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %y5v = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> <i8 undef, i8 undef>, <2 x i8> %a) + ret <2 x i8> %y5v +} + +define i8 @ssub_scalar_same(i8 %a) { +; CHECK-LABEL: @ssub_scalar_same( +; CHECK-NEXT: ret i8 0 +; + %y6 = call i8 @llvm.ssub.sat.i8(i8 %a, i8 %a) + ret i8 %y6 +} + +define <2 x i8> @ssub_vector_same(<2 x i8> %a) { +; CHECK-LABEL: @ssub_vector_same( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %y6v = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %a, <2 x i8> %a) + ret <2 x i8> %y6v +} + +define i1 @uadd_icmp_op0_known(i8 %a) { +; CHECK-LABEL: @uadd_icmp_op0_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.uadd.sat.i8(i8 10, i8 %a) + %c = icmp uge i8 %b, 10 + ret i1 %c +} + +define i1 @uadd_icmp_op0_unknown(i8 %a) { +; CHECK-LABEL: @uadd_icmp_op0_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.uadd.sat.i8(i8 10, i8 [[A:%.*]]) +; CHECK-NEXT: [[C:%.*]] = icmp ugt i8 [[B]], 10 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.uadd.sat.i8(i8 10, i8 %a) + %c = icmp ugt i8 %b, 10 + ret i1 %c +} + +define i1 @uadd_icmp_op1_known(i8 %a) { +; CHECK-LABEL: @uadd_icmp_op1_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.uadd.sat.i8(i8 %a, i8 10) + %c = icmp uge i8 %b, 10 + ret i1 %c +} + +define i1 @uadd_icmp_op1_unknown(i8 %a) { +; CHECK-LABEL: @uadd_icmp_op1_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[A:%.*]], i8 10) +; CHECK-NEXT: [[C:%.*]] = icmp ugt i8 [[B]], 10 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.uadd.sat.i8(i8 %a, i8 10) + %c = icmp ugt i8 %b, 10 + ret i1 %c +} + +define i1 @sadd_icmp_op0_pos_known(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op0_pos_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.sadd.sat.i8(i8 10, i8 %a) + %c = icmp sge i8 %b, -118 + ret i1 %c +} + +define i1 @sadd_icmp_op0_pos_unknown(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op0_pos_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 10, i8 [[A:%.*]]) +; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[B]], -118 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.sadd.sat.i8(i8 10, i8 %a) + %c = icmp sgt i8 %b, -118 + ret i1 %c +} + +define i1 @sadd_icmp_op0_neg_known(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op0_neg_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.sadd.sat.i8(i8 -10, i8 %a) + %c = icmp sle i8 %b, 117 + ret i1 %c +} + +define i1 @sadd_icmp_op0_neg_unknown(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op0_neg_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 -10, i8 [[A:%.*]]) +; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], 117 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.sadd.sat.i8(i8 -10, i8 %a) + %c = icmp slt i8 %b, 117 + ret i1 %c +} + +define i1 @sadd_icmp_op1_pos_known(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op1_pos_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.sadd.sat.i8(i8 %a, i8 10) + %c = icmp sge i8 %b, -118 + ret i1 %c +} + +define i1 @sadd_icmp_op1_pos_unknown(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op1_pos_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[A:%.*]], i8 10) +; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[B]], -118 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.sadd.sat.i8(i8 %a, i8 10) + %c = icmp sgt i8 %b, -118 + ret i1 %c +} + +define i1 @sadd_icmp_op1_neg_known(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op1_neg_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.sadd.sat.i8(i8 %a, i8 -10) + %c = icmp sle i8 %b, 117 + ret i1 %c +} + +define i1 @sadd_icmp_op1_neg_unknown(i8 %a) { +; CHECK-LABEL: @sadd_icmp_op1_neg_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[A:%.*]], i8 -10) +; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], 117 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.sadd.sat.i8(i8 %a, i8 -10) + %c = icmp slt i8 %b, 117 + ret i1 %c +} + +define i1 @usub_icmp_op0_known(i8 %a) { +; CHECK-LABEL: @usub_icmp_op0_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.usub.sat.i8(i8 10, i8 %a) + %c = icmp ule i8 %b, 10 + ret i1 %c +} + +define i1 @usub_icmp_op0_unknown(i8 %a) { +; CHECK-LABEL: @usub_icmp_op0_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.usub.sat.i8(i8 10, i8 [[A:%.*]]) +; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[B]], 10 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.usub.sat.i8(i8 10, i8 %a) + %c = icmp ult i8 %b, 10 + ret i1 %c +} + +define i1 @usub_icmp_op1_known(i8 %a) { +; CHECK-LABEL: @usub_icmp_op1_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.usub.sat.i8(i8 %a, i8 10) + %c = icmp ule i8 %b, 245 + ret i1 %c +} + +define i1 @usub_icmp_op1_unknown(i8 %a) { +; CHECK-LABEL: @usub_icmp_op1_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 10) +; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[B]], -11 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.usub.sat.i8(i8 %a, i8 10) + %c = icmp ult i8 %b, 245 + ret i1 %c +} + +define i1 @ssub_icmp_op0_pos_known(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op0_pos_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.ssub.sat.i8(i8 10, i8 %a) + %c = icmp sge i8 %b, -117 + ret i1 %c +} + +define i1 @ssub_icmp_op0_pos_unknown(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op0_pos_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 10, i8 [[A:%.*]]) +; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[B]], -117 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.ssub.sat.i8(i8 10, i8 %a) + %c = icmp sgt i8 %b, -117 + ret i1 %c +} + +define i1 @ssub_icmp_op0_neg_known(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op0_neg_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.ssub.sat.i8(i8 -10, i8 %a) + %c = icmp sle i8 %b, 118 + ret i1 %c +} + +define i1 @ssub_icmp_op0_neg_unknown(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op0_neg_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 -10, i8 [[A:%.*]]) +; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], 118 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.ssub.sat.i8(i8 -10, i8 %a) + %c = icmp slt i8 %b, 118 + ret i1 %c +} + +; Peculiar case: ssub.sat(0, x) is never signed min. +define i1 @ssub_icmp_op0_zero(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op0_zero( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.ssub.sat.i8(i8 0, i8 %a) + %c = icmp ne i8 %b, -128 + ret i1 %c +} + +define i1 @ssub_icmp_op1_pos_known(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op1_pos_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 10) + %c = icmp sle i8 %b, 117 + ret i1 %c +} + +define i1 @ssub_icmp_op1_pos_unknown(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op1_pos_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A:%.*]], i8 10) +; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], 117 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 10) + %c = icmp slt i8 %b, 117 + ret i1 %c +} + +define i1 @ssub_icmp_op1_neg_known(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op1_neg_known( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 -10) + %c = icmp sge i8 %b, -118 + ret i1 %c +} + +define i1 @ssub_icmp_op1_neg_unknown(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op1_neg_unknown( +; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.ssub.sat.i8(i8 [[A:%.*]], i8 -10) +; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[B]], -118 +; CHECK-NEXT: ret i1 [[C]] +; + %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 -10) + %c = icmp sgt i8 %b, -118 + ret i1 %c +} + +define i1 @ssub_icmp_op1_smin(i8 %a) { +; CHECK-LABEL: @ssub_icmp_op1_smin( +; CHECK-NEXT: ret i1 true +; + %b = call i8 @llvm.ssub.sat.i8(i8 %a, i8 -128) + %c = icmp sge i8 %b, 0 + ret i1 %c +} diff --git a/llvm/test/Transforms/InstSimplify/sdiv.ll b/llvm/test/Transforms/InstSimplify/sdiv.ll new file mode 100644 index 00000000000..76ba16800c2 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/sdiv.ll @@ -0,0 +1,179 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @negated_operand(i32 %x) { +; CHECK-LABEL: @negated_operand( +; CHECK-NEXT: ret i32 -1 +; + %negx = sub nsw i32 0, %x + %div = sdiv i32 %negx, %x + ret i32 %div +} + +define <2 x i32> @negated_operand_commute_vec(<2 x i32> %x) { +; CHECK-LABEL: @negated_operand_commute_vec( +; CHECK-NEXT: ret <2 x i32> <i32 -1, i32 -1> +; + %negx = sub nsw <2 x i32> zeroinitializer, %x + %div = sdiv <2 x i32> %negx, %x + ret <2 x i32> %div +} + +define i32 @knownnegation(i32 %x, i32 %y) { +; CHECK-LABEL: @knownnegation( +; CHECK-NEXT: ret i32 -1 +; + %xy = sub nsw i32 %x, %y + %yx = sub nsw i32 %y, %x + %div = sdiv i32 %xy, %yx + ret i32 %div +} + +define <2 x i32> @knownnegation_commute_vec(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @knownnegation_commute_vec( +; CHECK-NEXT: ret <2 x i32> <i32 -1, i32 -1> +; + %xy = sub nsw <2 x i32> %x, %y + %yx = sub nsw <2 x i32> %y, %x + %div = sdiv <2 x i32> %xy, %yx + ret <2 x i32> %div +} + +define i32 @negated_operand_2(i32 %t) { +; CHECK-LABEL: @negated_operand_2( +; CHECK-NEXT: ret i32 -1 +; + %x = sub i32 %t, 5 + %negx = sub nsw i32 0, %x + %div = sdiv i32 %negx, %x + ret i32 %div +} + +define i32 @negated_operand_commute(i32 %x) { +; CHECK-LABEL: @negated_operand_commute( +; CHECK-NEXT: ret i32 -1 +; + %negx = sub nsw i32 0, %x + %div = sdiv i32 %x, %negx + ret i32 %div +} + +define i32 @negated_operand_bad(i32 %x) { +; CHECK-LABEL: @negated_operand_bad( +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[NEGX]], [[X]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %negx = sub i32 0, %x ; not nsw + %div = sdiv i32 %negx, %x + ret i32 %div +} + +define i32 @knownnegation_bad_1(i32 %x, i32 %y) { +; CHECK-LABEL: @knownnegation_bad_1( +; CHECK-NEXT: [[XY:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[YX:%.*]] = sub i32 [[Y]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[XY]], [[YX]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %xy = sub nsw i32 %x, %y + %yx = sub i32 %y, %x ; not nsw + %div = sdiv i32 %xy, %yx + ret i32 %div +} + +define i32 @knownnegation_bad_2(i32 %x, i32 %y) { +; CHECK-LABEL: @knownnegation_bad_2( +; CHECK-NEXT: [[XY:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[YX:%.*]] = sub nsw i32 [[Y]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[XY]], [[YX]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %xy = sub i32 %x, %y ; not nsw + %yx = sub nsw i32 %y, %x + %div = sdiv i32 %xy, %yx + ret i32 %div +} + +define i32 @knownnegation_bad_3(i32 %x, i32 %y) { +; CHECK-LABEL: @knownnegation_bad_3( +; CHECK-NEXT: [[XY:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[YX:%.*]] = sub i32 [[Y]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[XY]], [[YX]] +; CHECK-NEXT: ret i32 [[DIV]] +; + %xy = sub i32 %x, %y ; not nsw + %yx = sub i32 %y, %x ; not nsw + %div = sdiv i32 %xy, %yx + ret i32 %div +} + +define <2 x i32> @negated_operand_commute_vec_bad(<2 x i32> %x) { +; CHECK-LABEL: @negated_operand_commute_vec_bad( +; CHECK-NEXT: [[NEGX:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i32> [[NEGX]], [[X]] +; CHECK-NEXT: ret <2 x i32> [[DIV]] +; + %negx = sub <2 x i32> zeroinitializer, %x ; not nsw + %div = sdiv <2 x i32> %negx, %x + ret <2 x i32> %div +} + +define <2 x i32> @knownnegation_commute_vec_bad1(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @knownnegation_commute_vec_bad1( +; CHECK-NEXT: [[XY:%.*]] = sub nsw <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[YX:%.*]] = sub <2 x i32> [[Y]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i32> [[XY]], [[YX]] +; CHECK-NEXT: ret <2 x i32> [[DIV]] +; + %xy = sub nsw <2 x i32> %x, %y + %yx = sub <2 x i32> %y, %x ; not nsw + %div = sdiv <2 x i32> %xy, %yx + ret <2 x i32> %div +} + +define <2 x i32> @knownnegation_commute_vec_bad2(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @knownnegation_commute_vec_bad2( +; CHECK-NEXT: [[XY:%.*]] = sub <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[YX:%.*]] = sub nsw <2 x i32> [[Y]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i32> [[XY]], [[YX]] +; CHECK-NEXT: ret <2 x i32> [[DIV]] +; + %xy = sub <2 x i32> %x, %y ; not nsw + %yx = sub nsw <2 x i32> %y, %x + %div = sdiv <2 x i32> %xy, %yx + ret <2 x i32> %div +} + +define <2 x i32> @knownnegation_commute_vec_bad3(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @knownnegation_commute_vec_bad3( +; CHECK-NEXT: [[XY:%.*]] = sub <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[YX:%.*]] = sub <2 x i32> [[Y]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i32> [[XY]], [[YX]] +; CHECK-NEXT: ret <2 x i32> [[DIV]] +; + %xy = sub <2 x i32> %x, %y ; not nsw + %yx = sub <2 x i32> %y, %x ; not nsw + %div = sdiv <2 x i32> %xy, %yx + ret <2 x i32> %div +} + +define <3 x i32> @negated_operand_vec_undef(<3 x i32> %x) { +; CHECK-LABEL: @negated_operand_vec_undef( +; CHECK-NEXT: ret <3 x i32> <i32 -1, i32 -1, i32 -1> +; + %negx = sub nsw <3 x i32> <i32 0, i32 undef, i32 0>, %x + %div = sdiv <3 x i32> %negx, %x + ret <3 x i32> %div +} + +define <2 x i32> @negated_operand_vec_nonsplat(<2 x i32> %x) { +; CHECK-LABEL: @negated_operand_vec_nonsplat( +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw <2 x i32> <i32 0, i32 1>, [[X:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i32> [[NEGX]], [[X]] +; CHECK-NEXT: ret <2 x i32> [[DIV]] +; + %negx = sub nsw <2 x i32> <i32 0, i32 1>, %x ; not 0, don't fold + %div = sdiv <2 x i32> %negx, %x + ret <2 x i32> %div +} diff --git a/llvm/test/Transforms/InstSimplify/select-and-cmp.ll b/llvm/test/Transforms/InstSimplify/select-and-cmp.ll new file mode 100644 index 00000000000..7153972c79c --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/select-and-cmp.ll @@ -0,0 +1,339 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @select_and_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define <2 x i8> @select_and_icmp_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { +; CHECK-LABEL: @select_and_icmp_vec( +; CHECK-NEXT: ret <2 x i8> [[X:%.*]] +; + %A = icmp eq <2 x i8> %x, %z + %B = icmp eq <2 x i8> %y, %z + %C = and <2 x i1> %A, %B + %D = select <2 x i1> %C, <2 x i8> %z, <2 x i8> %x + ret <2 x i8> %D +} + +define i32 @select_and_icmp2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp2( +; CHECK-NEXT: ret i32 [[Y:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %y + ret i32 %D +} + +define i32 @select_and_icmp_alt(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_alt( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_alt2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_alt2( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %y, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_inv_alt(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_inv_alt( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp eq i32 %z, %x + %B = icmp eq i32 %z, %y + %C = and i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_inv_icmp_alt(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_inv_icmp_alt( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %B, %A + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_inv_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_inv_icmp( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %B , %A + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define <2 x i8> @select_and_icmp_alt_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { +; CHECK-LABEL: @select_and_icmp_alt_vec( +; CHECK-NEXT: ret <2 x i8> [[Z:%.*]] +; + %A = icmp eq <2 x i8> %x, %z + %B = icmp eq <2 x i8> %y, %z + %C = and <2 x i1> %A, %B + %D = select <2 x i1> %C, <2 x i8> %x, <2 x i8> %z + ret <2 x i8> %D +} + + +define i32 @select_and_icmp_inv(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_inv( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp eq i32 %z, %x + %B = icmp eq i32 %z, %y + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +; Negative tests +define i32 @select_and_icmp_pred_bad_1(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_1( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp ne i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_pred_bad_2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_2( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_pred_bad_3(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_3( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_pred_bad_4(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_4( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_bad_true_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_and_icmp_bad_true_val( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[K:%.*]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %k, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_bad_false_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_and_icmp_bad_false_val( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[K:%.*]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %k + ret i32 %D +} + +define i32 @select_and_icmp_bad_op(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_and_icmp_bad_op( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[K:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X:%.*]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %k, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_bad_op_2(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_and_icmp_bad_op_2( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[K:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %k + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_alt_bad_1(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_alt_bad_1( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp ne i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_alt_bad_2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_alt_bad_2( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_alt_bad_3(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_alt_bad_3( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_alt_bad_4(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_alt_bad_4( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_alt_bad_5(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_and_icmp_alt_bad_5( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[K:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %k + %B = icmp eq i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_alt_bad_true_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_and_icmp_alt_bad_true_val( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[K:%.*]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %k, i32 %z + ret i32 %D +} + +define i32 @select_and_icmp_alt_bad_false_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_and_icmp_alt_bad_false_val( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[K:%.*]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %x, i32 %k + ret i32 %D +} diff --git a/llvm/test/Transforms/InstSimplify/select-implied.ll b/llvm/test/Transforms/InstSimplify/select-implied.ll new file mode 100644 index 00000000000..a456e291b51 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/select-implied.ll @@ -0,0 +1,276 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; A == B implies A >u B is false. + +define void @test1(i32 %a, i32 %b) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] +; CHECK: taken: +; CHECK-NEXT: call void @foo(i32 10) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %end + +taken: + %cmp2 = icmp ugt i32 %a, %b + %c = select i1 %cmp2, i32 0, i32 10 + call void @foo(i32 %c) + br label %end + +end: + ret void +} + +; If A == B is false then A != B is true. + +define void @test2(i32 %a, i32 %b) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br i1 [[CMP1]], label [[END:%.*]], label [[TAKEN:%.*]] +; CHECK: taken: +; CHECK-NEXT: call void @foo(i32 20) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %end, label %taken + +taken: + %cmp2 = icmp ne i32 %a, %b + %c = select i1 %cmp2, i32 20, i32 0 + call void @foo(i32 %c) + br label %end + +end: + ret void +} + +; A >u 10 implies A >u 10 is true. + +define void @test3(i32 %a) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 10 +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] +; CHECK: taken: +; CHECK-NEXT: call void @foo(i32 30) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; + %cmp1 = icmp ugt i32 %a, 10 + br i1 %cmp1, label %taken, label %end + +taken: + %cmp2 = icmp ugt i32 %a, 10 + %c = select i1 %cmp2, i32 30, i32 0 + call void @foo(i32 %c) + br label %end + +end: + ret void +} + +define i8 @PR23333(i8 addrspace(1)* %ptr) { +; CHECK-LABEL: @PR23333( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 addrspace(1)* [[PTR:%.*]], null +; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[END:%.*]] +; CHECK: taken: +; CHECK-NEXT: ret i8 1 +; CHECK: end: +; CHECK-NEXT: ret i8 0 +; + %cmp = icmp eq i8 addrspace(1)* %ptr, null + br i1 %cmp, label %taken, label %end + +taken: + %cmp2 = icmp ne i8 addrspace(1)* %ptr, null + %res = select i1 %cmp2, i8 2, i8 1 + ret i8 %res + +end: + ret i8 0 +} + +; We know the condition of the select is true based on a dominating condition. +; Therefore, we can replace %cond with %len. +; TODO: len == 8 is known false in bb. This is handled by other passes, but should it be handled here? + +define void @test4(i32 %len) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = call i32 @bar(i32 [[LEN:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LEN]], 4 +; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[B1:%.*]] +; CHECK: bb: +; CHECK-NEXT: [[CMP11:%.*]] = icmp eq i32 [[LEN]], 8 +; CHECK-NEXT: br i1 [[CMP11]], label [[B0:%.*]], label [[B1]] +; CHECK: b0: +; CHECK-NEXT: call void @foo(i32 [[LEN]]) +; CHECK-NEXT: br label [[B1]] +; CHECK: b1: +; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[LEN]], [[BB]] ], [ undef, [[B0]] ], [ [[TMP0]], [[ENTRY:%.*]] ] +; CHECK-NEXT: br label [[RET:%.*]] +; CHECK: ret: +; CHECK-NEXT: call void @foo(i32 [[TMP1]]) +; CHECK-NEXT: ret void +; +entry: + %0 = call i32 @bar(i32 %len); + %cmp = icmp ult i32 %len, 4 + br i1 %cmp, label %bb, label %b1 +bb: + %cond = select i1 %cmp, i32 %len, i32 8 + %cmp11 = icmp eq i32 %cond, 8 + br i1 %cmp11, label %b0, label %b1 + +b0: + call void @foo(i32 %len) + br label %b1 + +b1: + %1 = phi i32 [ %cond, %bb ], [ undef, %b0 ], [ %0, %entry ] + br label %ret + +ret: + call void @foo(i32 %1) + ret void +} + +; A >u 10 implies A >u 9 is true. + +define void @test5(i32 %a) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 10 +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] +; CHECK: taken: +; CHECK-NEXT: call void @foo(i32 30) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; + %cmp1 = icmp ugt i32 %a, 10 + br i1 %cmp1, label %taken, label %end + +taken: + %cmp2 = icmp ugt i32 %a, 9 + %c = select i1 %cmp2, i32 30, i32 0 + call void @foo(i32 %c) + br label %end + +end: + ret void +} + +declare void @foo(i32) +declare i32 @bar(i32) + +define i32 @test_and(i32 %a, i32 %b) { +; CHECK-LABEL: @test_and( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 0 +; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[B:%.*]], 0 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: br i1 [[AND]], label [[TPATH:%.*]], label [[END:%.*]] +; CHECK: tpath: +; CHECK-NEXT: ret i32 313 +; CHECK: end: +; CHECK-NEXT: ret i32 0 +; +entry: + %cmp1 = icmp ne i32 %a, 0 + %cmp2 = icmp ne i32 %b, 0 + %and = and i1 %cmp1, %cmp2 + br i1 %and, label %tpath, label %end + +tpath: + %cmp3 = icmp eq i32 %a, 0 ;; <-- implied false + %c = select i1 %cmp3, i32 0, i32 313 + ret i32 %c + +end: + ret i32 0 +} + +; cmp1 and cmp2 are false on the 'fpath' path and thus cmp3 is true. + +define i32 @test_or1(i32 %a, i32 %b) { +; CHECK-LABEL: @test_or1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 0 +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[B:%.*]], 0 +; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: br i1 [[OR]], label [[END:%.*]], label [[FPATH:%.*]] +; CHECK: fpath: +; CHECK-NEXT: ret i32 37 +; CHECK: end: +; CHECK-NEXT: ret i32 0 +; +entry: + %cmp1 = icmp eq i32 %a, 0 + %cmp2 = icmp eq i32 %b, 0 + %or = or i1 %cmp1, %cmp2 + br i1 %or, label %end, label %fpath + +fpath: + %cmp3 = icmp ne i32 %a, 0 ;; <-- implied true + %c = select i1 %cmp3, i32 37, i32 0 + ret i32 %c + +end: + ret i32 0 +} + +; LHS ==> RHS by definition (true -> true) + +define void @test6(i32 %a, i32 %b) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] +; CHECK: taken: +; CHECK-NEXT: call void @foo(i32 10) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %end + +taken: + %c = select i1 %cmp1, i32 10, i32 0 + call void @foo(i32 %c) + br label %end + +end: + ret void +} + +; LHS ==> RHS by definition (false -> false) + +define void @test7(i32 %a, i32 %b) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br i1 [[CMP1]], label [[END:%.*]], label [[TAKEN:%.*]] +; CHECK: taken: +; CHECK-NEXT: call void @foo(i32 11) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret void +; + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %end, label %taken + +taken: + %c = select i1 %cmp1, i32 0, i32 11 + call void @foo(i32 %c) + br label %end + +end: + ret void +} + diff --git a/llvm/test/Transforms/InstSimplify/select-or-cmp.ll b/llvm/test/Transforms/InstSimplify/select-or-cmp.ll new file mode 100644 index 00000000000..ea29bff7d1c --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/select-or-cmp.ll @@ -0,0 +1,339 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @select_or_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define <2 x i8> @select_or_icmp_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { +; CHECK-LABEL: @select_or_icmp_vec( +; CHECK-NEXT: ret <2 x i8> [[Z:%.*]] +; + %A = icmp ne <2 x i8> %x, %z + %B = icmp ne <2 x i8> %y, %z + %C = or <2 x i1> %A, %B + %D = select <2 x i1> %C, <2 x i8> %z, <2 x i8> %x + ret <2 x i8> %D +} + +define i32 @select_or_icmp2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp2( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %y + ret i32 %D +} + +define i32 @select_or_icmp_alt(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_alt( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_alt2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_alt2( +; CHECK-NEXT: ret i32 [[Y:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %y, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_inv_alt(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_inv_alt( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp ne i32 %z, %x + %B = icmp ne i32 %z, %y + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_or_inv_icmp_alt(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_inv_icmp_alt( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp ne i32 %z, %x + %B = icmp ne i32 %z, %y + %C = or i1 %B, %A + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define <2 x i8> @select_or_icmp_alt_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { +; CHECK-LABEL: @select_or_icmp_alt_vec( +; CHECK-NEXT: ret <2 x i8> [[X:%.*]] +; + %A = icmp ne <2 x i8> %x, %z + %B = icmp ne <2 x i8> %y, %z + %C = or <2 x i1> %A, %B + %D = select <2 x i1> %C, <2 x i8> %x, <2 x i8> %z + ret <2 x i8> %D +} + +define i32 @select_or_inv_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_inv_icmp( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %B , %A + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_or_icmp_inv(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_inv( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %z, %x + %B = icmp ne i32 %z, %y + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +; Negative tests +define i32 @select_and_icmp_pred_bad_1(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_1( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_pred_bad_2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_2( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp eq i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_pred_bad_3(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_3( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_pred_bad_4(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_pred_bad_4( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_or_icmp_bad_true_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_or_icmp_bad_true_val( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[K:%.*]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %k, i32 %x + ret i32 %D +} + +define i32 @select_or_icmp_bad_false_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_or_icmp_bad_false_val( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[K:%.*]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %k + ret i32 %D +} + +define i32 @select_or_icmp_bad_op(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_or_icmp_bad_op( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[K:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X:%.*]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %k, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + + +define i32 @select_or_icmp_bad_op_2(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_or_icmp_bad_op_2( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[K:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %k + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_or_icmp_alt_bad_1(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_alt_bad_1( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_alt_bad_2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_alt_bad_2( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp eq i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_alt_bad_3(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_alt_bad_3( +; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_alt_bad_4(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_alt_bad_4( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_alt_bad_5(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_or_icmp_alt_bad_5( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[K:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %k + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_alt_bad_true_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_or_icmp_alt_bad_true_val( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[K:%.*]], i32 [[Z]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %k, i32 %z + ret i32 %D +} + +define i32 @select_or_icmp_alt_bad_false_val(i32 %x, i32 %y, i32 %z, i32 %k) { +; CHECK-LABEL: @select_or_icmp_alt_bad_false_val( +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] +; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X]], i32 [[K:%.*]] +; CHECK-NEXT: ret i32 [[D]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %x, i32 %k + ret i32 %D +} diff --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll new file mode 100644 index 00000000000..d640805f86b --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/select.ll @@ -0,0 +1,566 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define <2 x i8> @vsel_tvec(<2 x i8> %x, <2 x i8> %y) { +; CHECK-LABEL: @vsel_tvec( +; CHECK-NEXT: ret <2 x i8> %x +; + %s = select <2 x i1><i1 true, i1 true>, <2 x i8> %x, <2 x i8> %y + ret <2 x i8> %s +} + +define <2 x i8> @vsel_fvec(<2 x i8> %x, <2 x i8> %y) { +; CHECK-LABEL: @vsel_fvec( +; CHECK-NEXT: ret <2 x i8> %y +; + %s = select <2 x i1><i1 false, i1 false>, <2 x i8> %x, <2 x i8> %y + ret <2 x i8> %s +} + +define <2 x i8> @vsel_mixedvec() { +; CHECK-LABEL: @vsel_mixedvec( +; CHECK-NEXT: ret <2 x i8> <i8 0, i8 3> +; + %s = select <2 x i1><i1 true, i1 false>, <2 x i8> <i8 0, i8 1>, <2 x i8> <i8 2, i8 3> + ret <2 x i8> %s +} + +; FIXME: Allow for undef elements in a constant vector condition. + +define <3 x i8> @vsel_undef_true_op(<3 x i8> %x, <3 x i8> %y) { +; CHECK-LABEL: @vsel_undef_true_op( +; CHECK-NEXT: [[S:%.*]] = select <3 x i1> <i1 true, i1 undef, i1 true>, <3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]] +; CHECK-NEXT: ret <3 x i8> [[S]] +; + %s = select <3 x i1><i1 1, i1 undef, i1 1>, <3 x i8> %x, <3 x i8> %y + ret <3 x i8> %s +} + +define <3 x i4> @vsel_undef_false_op(<3 x i4> %x, <3 x i4> %y) { +; CHECK-LABEL: @vsel_undef_false_op( +; CHECK-NEXT: [[S:%.*]] = select <3 x i1> <i1 false, i1 undef, i1 undef>, <3 x i4> [[X:%.*]], <3 x i4> [[Y:%.*]] +; CHECK-NEXT: ret <3 x i4> [[S]] +; + %s = select <3 x i1><i1 0, i1 undef, i1 undef>, <3 x i4> %x, <3 x i4> %y + ret <3 x i4> %s +} + +define i32 @test1(i32 %x) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: ret i32 %x +; + %and = and i32 %x, 1 + %cmp = icmp eq i32 %and, 0 + %and1 = and i32 %x, -2 + %and1.x = select i1 %cmp, i32 %and1, i32 %x + ret i32 %and1.x +} + +define i32 @test2(i32 %x) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: ret i32 %x +; + %and = and i32 %x, 1 + %cmp = icmp ne i32 %and, 0 + %and1 = and i32 %x, -2 + %and1.x = select i1 %cmp, i32 %x, i32 %and1 + ret i32 %and1.x +} + +define i32 @test3(i32 %x) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: [[AND1:%.*]] = and i32 %x, -2 +; CHECK-NEXT: ret i32 [[AND1]] +; + %and = and i32 %x, 1 + %cmp = icmp ne i32 %and, 0 + %and1 = and i32 %x, -2 + %and1.x = select i1 %cmp, i32 %and1, i32 %x + ret i32 %and1.x +} + +define i32 @test4(i32 %X) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: [[OR:%.*]] = or i32 %X, -2147483648 +; CHECK-NEXT: ret i32 [[OR]] +; + %cmp = icmp slt i32 %X, 0 + %or = or i32 %X, -2147483648 + %cond = select i1 %cmp, i32 %X, i32 %or + ret i32 %cond +} + +; Same as above, but the compare isn't canonical +define i32 @test4noncanon(i32 %X) { +; CHECK-LABEL: @test4noncanon( +; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], -2147483648 +; CHECK-NEXT: ret i32 [[OR]] +; + %cmp = icmp sle i32 %X, -1 + %or = or i32 %X, -2147483648 + %cond = select i1 %cmp, i32 %X, i32 %or + ret i32 %cond +} + +define i32 @test5(i32 %X) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: ret i32 %X +; + %cmp = icmp slt i32 %X, 0 + %or = or i32 %X, -2147483648 + %cond = select i1 %cmp, i32 %or, i32 %X + ret i32 %cond +} + +define i32 @test6(i32 %X) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: [[AND:%.*]] = and i32 %X, 2147483647 +; CHECK-NEXT: ret i32 [[AND]] +; + %cmp = icmp slt i32 %X, 0 + %and = and i32 %X, 2147483647 + %cond = select i1 %cmp, i32 %and, i32 %X + ret i32 %cond +} + +define i32 @test7(i32 %X) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: ret i32 %X +; + %cmp = icmp slt i32 %X, 0 + %and = and i32 %X, 2147483647 + %cond = select i1 %cmp, i32 %X, i32 %and + ret i32 %cond +} + +define i32 @test8(i32 %X) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: ret i32 %X +; + %cmp = icmp sgt i32 %X, -1 + %or = or i32 %X, -2147483648 + %cond = select i1 %cmp, i32 %X, i32 %or + ret i32 %cond +} + +define i32 @test9(i32 %X) { +; CHECK-LABEL: @test9( +; CHECK-NEXT: [[OR:%.*]] = or i32 %X, -2147483648 +; CHECK-NEXT: ret i32 [[OR]] +; + %cmp = icmp sgt i32 %X, -1 + %or = or i32 %X, -2147483648 + %cond = select i1 %cmp, i32 %or, i32 %X + ret i32 %cond +} + +; Same as above, but the compare isn't canonical +define i32 @test9noncanon(i32 %X) { +; CHECK-LABEL: @test9noncanon( +; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], -2147483648 +; CHECK-NEXT: ret i32 [[OR]] +; + %cmp = icmp sge i32 %X, 0 + %or = or i32 %X, -2147483648 + %cond = select i1 %cmp, i32 %or, i32 %X + ret i32 %cond +} + +define i32 @test10(i32 %X) { +; CHECK-LABEL: @test10( +; CHECK-NEXT: ret i32 %X +; + %cmp = icmp sgt i32 %X, -1 + %and = and i32 %X, 2147483647 + %cond = select i1 %cmp, i32 %and, i32 %X + ret i32 %cond +} + +define i32 @test11(i32 %X) { +; CHECK-LABEL: @test11( +; CHECK-NEXT: [[AND:%.*]] = and i32 %X, 2147483647 +; CHECK-NEXT: ret i32 [[AND]] +; + %cmp = icmp sgt i32 %X, -1 + %and = and i32 %X, 2147483647 + %cond = select i1 %cmp, i32 %X, i32 %and + ret i32 %cond +} + +define <2 x i8> @test11vec(<2 x i8> %X) { +; CHECK-LABEL: @test11vec( +; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> %X, <i8 127, i8 127> +; CHECK-NEXT: ret <2 x i8> [[AND]] +; + %cmp = icmp sgt <2 x i8> %X, <i8 -1, i8 -1> + %and = and <2 x i8> %X, <i8 127, i8 127> + %sel = select <2 x i1> %cmp, <2 x i8> %X, <2 x i8> %and + ret <2 x i8> %sel +} + +define i32 @test12(i32 %X) { +; CHECK-LABEL: @test12( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3 +; CHECK-NEXT: ret i32 [[AND]] +; + %cmp = icmp ult i32 %X, 4 + %and = and i32 %X, 3 + %cond = select i1 %cmp, i32 %X, i32 %and + ret i32 %cond +} + +; Same as above, but the compare isn't canonical +define i32 @test12noncanon(i32 %X) { +; CHECK-LABEL: @test12noncanon( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3 +; CHECK-NEXT: ret i32 [[AND]] +; + %cmp = icmp ule i32 %X, 3 + %and = and i32 %X, 3 + %cond = select i1 %cmp, i32 %X, i32 %and + ret i32 %cond +} + +define i32 @test13(i32 %X) { +; CHECK-LABEL: @test13( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3 +; CHECK-NEXT: ret i32 [[AND]] +; + %cmp = icmp ugt i32 %X, 3 + %and = and i32 %X, 3 + %cond = select i1 %cmp, i32 %and, i32 %X + ret i32 %cond +} + +; Same as above, but the compare isn't canonical +define i32 @test13noncanon(i32 %X) { +; CHECK-LABEL: @test13noncanon( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3 +; CHECK-NEXT: ret i32 [[AND]] +; + %cmp = icmp uge i32 %X, 4 + %and = and i32 %X, 3 + %cond = select i1 %cmp, i32 %and, i32 %X + ret i32 %cond +} + +define i32 @select_icmp_and_8_eq_0_or_8(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_eq_0_or_8( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 8 +; CHECK-NEXT: ret i32 [[OR]] +; + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %x, 8 + %sel = select i1 %cmp, i32 %or, i32 %x + ret i32 %sel +} + +define i32 @select_icmp_and_8_eq_0_or_8_alt(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_eq_0_or_8_alt( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 8 +; CHECK-NEXT: ret i32 [[OR]] +; + %and = and i32 %x, 8 + %cmp = icmp ne i32 %and, 0 + %or = or i32 %x, 8 + %sel = select i1 %cmp, i32 %x, i32 %or + ret i32 %sel +} + +define i32 @select_icmp_and_8_ne_0_or_8(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_ne_0_or_8( +; CHECK-NEXT: ret i32 %x +; + %and = and i32 %x, 8 + %cmp = icmp ne i32 %and, 0 + %or = or i32 %x, 8 + %sel = select i1 %cmp, i32 %or, i32 %x + ret i32 %sel +} + +define i32 @select_icmp_and_8_ne_0_or_8_alt(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_ne_0_or_8_alt( +; CHECK-NEXT: ret i32 %x +; + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %x, 8 + %sel = select i1 %cmp, i32 %x, i32 %or + ret i32 %sel +} + +define i32 @select_icmp_and_8_eq_0_and_not_8(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_eq_0_and_not_8( +; CHECK-NEXT: [[AND1:%.*]] = and i32 %x, -9 +; CHECK-NEXT: ret i32 [[AND1]] +; + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %and1 = and i32 %x, -9 + %sel = select i1 %cmp, i32 %x, i32 %and1 + ret i32 %sel +} + +define i32 @select_icmp_and_8_eq_0_and_not_8_alt(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_eq_0_and_not_8_alt( +; CHECK-NEXT: [[AND1:%.*]] = and i32 %x, -9 +; CHECK-NEXT: ret i32 [[AND1]] +; + %and = and i32 %x, 8 + %cmp = icmp ne i32 %and, 0 + %and1 = and i32 %x, -9 + %sel = select i1 %cmp, i32 %and1, i32 %x + ret i32 %sel +} + +define i32 @select_icmp_and_8_ne_0_and_not_8(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8( +; CHECK-NEXT: ret i32 %x +; + %and = and i32 %x, 8 + %cmp = icmp ne i32 %and, 0 + %and1 = and i32 %x, -9 + %sel = select i1 %cmp, i32 %x, i32 %and1 + ret i32 %sel +} + +define i32 @select_icmp_and_8_ne_0_and_not_8_alt(i32 %x) { +; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8_alt( +; CHECK-NEXT: ret i32 %x +; + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %and1 = and i32 %x, -9 + %sel = select i1 %cmp, i32 %and1, i32 %x + ret i32 %sel +} + +; PR28466: https://llvm.org/bugs/show_bug.cgi?id=28466 +; Each of the previous 8 patterns has a variant that replaces the +; 'and' with a 'trunc' and the icmp eq/ne with icmp slt/sgt. + +define i32 @select_icmp_trunc_8_ne_0_or_128(i32 %x) { +; CHECK-LABEL: @select_icmp_trunc_8_ne_0_or_128( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128 +; CHECK-NEXT: ret i32 [[OR]] +; + %trunc = trunc i32 %x to i8 + %cmp = icmp sgt i8 %trunc, -1 + %or = or i32 %x, 128 + %sel = select i1 %cmp, i32 %or, i32 %x + ret i32 %sel +} + +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: [[OR:%.*]] = or i32 %x, 128 +; CHECK-NEXT: ret i32 [[OR]] +; + %trunc = trunc i32 %x to i8 + %cmp = icmp slt i8 %trunc, 0 + %or = or i32 %x, 128 + %sel = select i1 %cmp, i32 %x, i32 %or + ret i32 %sel +} + +define i32 @select_icmp_trunc_8_eq_0_or_128(i32 %x) { +; CHECK-LABEL: @select_icmp_trunc_8_eq_0_or_128( +; CHECK-NEXT: ret i32 %x +; + %trunc = trunc i32 %x to i8 + %cmp = icmp slt i8 %trunc, 0 + %or = or i32 %x, 128 + %sel = select i1 %cmp, i32 %or, i32 %x + ret i32 %sel +} + +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: ret i32 %x +; + %trunc = trunc i32 %x to i8 + %cmp = icmp sgt i8 %trunc, -1 + %or = or i32 %x, 128 + %sel = select i1 %cmp, i32 %x, i32 %or + ret i32 %sel +} + +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: [[AND:%.*]] = and i32 %x, -9 +; CHECK-NEXT: ret i32 [[AND]] +; + %trunc = trunc i32 %x to i4 + %cmp = icmp sgt i4 %trunc, -1 + %and = and i32 %x, -9 + %sel = select i1 %cmp, i32 %x, i32 %and + ret i32 %sel +} + +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: [[AND:%.*]] = and i32 %x, -9 +; CHECK-NEXT: ret i32 [[AND]] +; + %trunc = trunc i32 %x to i4 + %cmp = icmp slt i4 %trunc, 0 + %and = and i32 %x, -9 + %sel = select i1 %cmp, i32 %and, i32 %x + ret i32 %sel +} + +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: ret i32 %x +; + %trunc = trunc i32 %x to i4 + %cmp = icmp slt i4 %trunc, 0 + %and = and i32 %x, -9 + %sel = select i1 %cmp, i32 %x, i32 %and + ret i32 %sel +} + +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: ret i32 %x +; + %trunc = trunc i32 %x to i4 + %cmp = icmp sgt i4 %trunc, -1 + %and = and i32 %x, -9 + %sel = select i1 %cmp, i32 %and, i32 %x + ret i32 %sel +} + +; Make sure that at least a few of the same patterns are repeated with vector types. + +define <2 x i32> @select_icmp_and_8_ne_0_and_not_8_vec(<2 x i32> %x) { +; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8_vec( +; CHECK-NEXT: ret <2 x i32> %x +; + %and = and <2 x i32> %x, <i32 8, i32 8> + %cmp = icmp ne <2 x i32> %and, zeroinitializer + %and1 = and <2 x i32> %x, <i32 -9, i32 -9> + %sel = select <2 x i1> %cmp, <2 x i32> %x, <2 x i32> %and1 + ret <2 x i32> %sel +} + +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: 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> + %and = and <2 x i32> %x, <i32 -9, i32 -9> + %sel = select <2 x i1> %cmp, <2 x i32> %and, <2 x i32> %x + ret <2 x i32> %sel +} + +; Insert a bit from x into y? This should be possible in InstCombine, but not InstSimplify? + +define i32 @select_icmp_x_and_8_eq_0_y_and_not_8(i32 %x, i32 %y) { +; CHECK-LABEL: @select_icmp_x_and_8_eq_0_y_and_not_8( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 8 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[AND1:%.*]] = and i32 %y, -9 +; CHECK-NEXT: [[Y_AND1:%.*]] = select i1 [[CMP]], i32 %y, i32 [[AND1]] +; CHECK-NEXT: ret i32 [[Y_AND1]] +; + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %and1 = and i32 %y, -9 + %y.and1 = select i1 %cmp, i32 %y, i32 %and1 + ret i32 %y.and1 +} + +define i64 @select_icmp_x_and_8_eq_0_y64_and_not_8(i32 %x, i64 %y) { +; CHECK-LABEL: @select_icmp_x_and_8_eq_0_y64_and_not_8( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 8 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[AND1:%.*]] = and i64 %y, -9 +; CHECK-NEXT: [[Y_AND1:%.*]] = select i1 [[CMP]], i64 %y, i64 [[AND1]] +; CHECK-NEXT: ret i64 [[Y_AND1]] +; + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %and1 = and i64 %y, -9 + %y.and1 = select i1 %cmp, i64 %y, i64 %and1 + ret i64 %y.and1 +} + +define i64 @select_icmp_x_and_8_ne_0_y64_and_not_8(i32 %x, i64 %y) { +; CHECK-LABEL: @select_icmp_x_and_8_ne_0_y64_and_not_8( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 8 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[AND1:%.*]] = and i64 %y, -9 +; CHECK-NEXT: [[AND1_Y:%.*]] = select i1 [[CMP]], i64 [[AND1]], i64 %y +; CHECK-NEXT: ret i64 [[AND1_Y]] +; + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %and1 = and i64 %y, -9 + %and1.y = select i1 %cmp, i64 %and1, i64 %y + ret i64 %and1.y +} + +; Don't crash on a pointer or aggregate type. + +define i32* @select_icmp_pointers(i32* %x, i32* %y) { +; CHECK-LABEL: @select_icmp_pointers( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32* %x, null +; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32* %x, i32* %y +; CHECK-NEXT: ret i32* [[SEL]] +; + %cmp = icmp slt i32* %x, null + %sel = select i1 %cmp, i32* %x, i32* %y + ret i32* %sel +} + +; If the condition is known, we don't need to select, but we're not +; doing this fold here to avoid compile-time cost. + +declare void @llvm.assume(i1) + +define i8 @assume_sel_cond(i1 %cond, i8 %x, i8 %y) { +; CHECK-LABEL: @assume_sel_cond( +; CHECK-NEXT: call void @llvm.assume(i1 %cond) +; CHECK-NEXT: [[SEL:%.*]] = select i1 %cond, i8 %x, i8 %y +; CHECK-NEXT: ret i8 [[SEL]] +; + call void @llvm.assume(i1 %cond) + %sel = select i1 %cond, i8 %x, i8 %y + ret i8 %sel +} + +define i8 @do_not_assume_sel_cond(i1 %cond, i8 %x, i8 %y) { +; CHECK-LABEL: @do_not_assume_sel_cond( +; CHECK-NEXT: [[NOTCOND:%.*]] = icmp eq i1 %cond, false +; CHECK-NEXT: call void @llvm.assume(i1 [[NOTCOND]]) +; CHECK-NEXT: [[SEL:%.*]] = select i1 %cond, i8 %x, i8 %y +; CHECK-NEXT: ret i8 [[SEL]] +; + %notcond = icmp eq i1 %cond, false + call void @llvm.assume(i1 %notcond) + %sel = select i1 %cond, i8 %x, i8 %y + ret i8 %sel +} + +define i32* @select_icmp_eq_0_gep_operand(i32* %base, i64 %n) { +; CHECK-LABEL: @select_icmp_eq_0_gep_operand( +; CHECK-NEXT: [[GEP:%.*]] = getelementptr +; CHECK-NEXT: ret i32* [[GEP]] + %cond = icmp eq i64 %n, 0 + %gep = getelementptr i32, i32* %base, i64 %n + %r = select i1 %cond, i32* %base, i32* %gep + ret i32* %r +} + +define i32* @select_icmp_ne_0_gep_operand(i32* %base, i64 %n) { +; CHECK-LABEL: @select_icmp_ne_0_gep_operand( +; CHECK-NEXT: [[GEP:%.*]] = getelementptr +; CHECK-NEXT: ret i32* [[GEP]] + %cond = icmp ne i64 %n, 0 + %gep = getelementptr i32, i32* %base, i64 %n + %r = select i1 %cond, i32* %gep, i32* %base + ret i32* %r +} diff --git a/llvm/test/Transforms/InstSimplify/shift-128-kb.ll b/llvm/test/Transforms/InstSimplify/shift-128-kb.ll new file mode 100644 index 00000000000..76f1da57bbf --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/shift-128-kb.ll @@ -0,0 +1,30 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py +; RUN: opt -S -instsimplify < %s | FileCheck %s + +target datalayout = "E-m:e-i64:64-n32:64" +target triple = "powerpc64-unknown-linux-gnu" + +define zeroext i1 @_Z10isNegativemj(i64 %Val, i32 zeroext %IntegerBitWidth) { +; CHECK-LABEL: @_Z10isNegativemj( +; CHECK: [[CONV:%.*]] = zext i32 %IntegerBitWidth to i64 +; CHECK-NEXT: [[SUB:%.*]] = sub i64 128, [[CONV]] +; CHECK-NEXT: [[CONV1:%.*]] = trunc i64 [[SUB]] to i32 +; CHECK-NEXT: [[CONV2:%.*]] = zext i64 %Val to i128 +; CHECK-NEXT: [[SH_PROM:%.*]] = zext i32 [[CONV1]] to i128 +; CHECK-NEXT: [[SHL:%.*]] = shl i128 [[CONV2]], [[SH_PROM]] +; CHECK-NEXT: [[SHR:%.*]] = ashr i128 [[SHL]], [[SH_PROM]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[SHR]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %conv = zext i32 %IntegerBitWidth to i64 + %sub = sub i64 128, %conv + %conv1 = trunc i64 %sub to i32 + %conv2 = zext i64 %Val to i128 + %sh_prom = zext i32 %conv1 to i128 + %shl = shl i128 %conv2, %sh_prom + %shr = ashr i128 %shl, %sh_prom + %cmp = icmp slt i128 %shr, 0 + ret i1 %cmp +} + diff --git a/llvm/test/Transforms/InstSimplify/shift-knownbits.ll b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll new file mode 100644 index 00000000000..63b9b76fd22 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/shift-knownbits.ll @@ -0,0 +1,190 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; If any bits of the shift amount are known to make it exceed or equal +; the number of bits in the type, the shift causes undefined behavior. + +define i32 @shl_amount_is_known_bogus(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_amount_is_known_bogus( +; CHECK-NEXT: ret i32 undef +; + %or = or i32 %b, 32 + %shl = shl i32 %a, %or + ret i32 %shl +} + +; Check some weird types and the other shift ops. + +define i31 @lshr_amount_is_known_bogus(i31 %a, i31 %b) { +; CHECK-LABEL: @lshr_amount_is_known_bogus( +; CHECK-NEXT: ret i31 undef +; + %or = or i31 %b, 31 + %shr = lshr i31 %a, %or + ret i31 %shr +} + +define i33 @ashr_amount_is_known_bogus(i33 %a, i33 %b) { +; CHECK-LABEL: @ashr_amount_is_known_bogus( +; CHECK-NEXT: ret i33 undef +; + %or = or i33 %b, 33 + %shr = ashr i33 %a, %or + ret i33 %shr +} + + +; If all valid bits of the shift amount are known 0, there's no shift. +; It doesn't matter if high bits are set because that would be undefined. +; Therefore, the only possible valid result of these shifts is %a. + +define i16 @ashr_amount_is_zero(i16 %a, i16 %b) { +; CHECK-LABEL: @ashr_amount_is_zero( +; CHECK-NEXT: ret i16 %a +; + %and = and i16 %b, 65520 ; 0xfff0 + %shr = ashr i16 %a, %and + ret i16 %shr +} + +define i300 @lshr_amount_is_zero(i300 %a, i300 %b) { +; CHECK-LABEL: @lshr_amount_is_zero( +; CHECK-NEXT: ret i300 %a +; + %and = and i300 %b, 2048 + %shr = lshr i300 %a, %and + ret i300 %shr +} + +define i9 @shl_amount_is_zero(i9 %a, i9 %b) { +; CHECK-LABEL: @shl_amount_is_zero( +; CHECK-NEXT: ret i9 %a +; + %and = and i9 %b, 496 ; 0x1f0 + %shl = shl i9 %a, %and + ret i9 %shl +} + + +; Verify that we've calculated the log2 boundary of valid bits correctly for a weird type. + +define i9 @shl_amount_is_not_known_zero(i9 %a, i9 %b) { +; CHECK-LABEL: @shl_amount_is_not_known_zero( +; CHECK-NEXT: [[AND:%.*]] = and i9 %b, -8 +; CHECK-NEXT: [[SHL:%.*]] = shl i9 %a, [[AND]] +; CHECK-NEXT: ret i9 [[SHL]] +; + %and = and i9 %b, 504 ; 0x1f8 + %shl = shl i9 %a, %and + ret i9 %shl +} + + +; For vectors, we need all scalar elements to meet the requirements to optimize. + +define <2 x i32> @ashr_vector_bogus(<2 x i32> %a, <2 x i32> %b) { +; CHECK-LABEL: @ashr_vector_bogus( +; CHECK-NEXT: ret <2 x i32> undef +; + %or = or <2 x i32> %b, <i32 32, i32 32> + %shr = ashr <2 x i32> %a, %or + ret <2 x i32> %shr +} + +; FIXME: This is undef, but computeKnownBits doesn't handle the union. +define <2 x i32> @shl_vector_bogus(<2 x i32> %a, <2 x i32> %b) { +; CHECK-LABEL: @shl_vector_bogus( +; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> %b, <i32 32, i32 64> +; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> %a, [[OR]] +; CHECK-NEXT: ret <2 x i32> [[SHL]] +; + %or = or <2 x i32> %b, <i32 32, i32 64> + %shl = shl <2 x i32> %a, %or + ret <2 x i32> %shl +} + +define <2 x i32> @lshr_vector_zero(<2 x i32> %a, <2 x i32> %b) { +; CHECK-LABEL: @lshr_vector_zero( +; CHECK-NEXT: ret <2 x i32> %a +; + %and = and <2 x i32> %b, <i32 64, i32 256> + %shr = lshr <2 x i32> %a, %and + ret <2 x i32> %shr +} + +; Make sure that weird vector types work too. +define <2 x i15> @shl_vector_zero(<2 x i15> %a, <2 x i15> %b) { +; CHECK-LABEL: @shl_vector_zero( +; CHECK-NEXT: ret <2 x i15> %a +; + %and = and <2 x i15> %b, <i15 1024, i15 1024> + %shl = shl <2 x i15> %a, %and + ret <2 x i15> %shl +} + +define <2 x i32> @shl_vector_for_real(<2 x i32> %a, <2 x i32> %b) { +; CHECK-LABEL: @shl_vector_for_real( +; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> %b, <i32 3, i32 3> +; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> %a, [[AND]] +; CHECK-NEXT: ret <2 x i32> [[SHL]] +; + %and = and <2 x i32> %b, <i32 3, i32 3> ; a necessary mask op + %shl = shl <2 x i32> %a, %and + ret <2 x i32> %shl +} + + +; We calculate the valid bits of the shift using log2, and log2 of 1 (the type width) is 0. +; That should be ok. Either the shift amount is 0 or invalid (1), so we can always return %a. + +define i1 @shl_i1(i1 %a, i1 %b) { +; CHECK-LABEL: @shl_i1( +; CHECK-NEXT: ret i1 %a +; + %shl = shl i1 %a, %b + ret i1 %shl +} + +; Simplify count leading/trailing zeros to zero if all valid bits are shifted out. + +declare i32 @llvm.cttz.i32(i32, i1) nounwind readnone +declare i32 @llvm.ctlz.i32(i32, i1) nounwind readnone +declare <2 x i8> @llvm.cttz.v2i8(<2 x i8>, i1) nounwind readnone +declare <2 x i8> @llvm.ctlz.v2i8(<2 x i8>, i1) nounwind readnone + +define i32 @lshr_ctlz_zero_is_undef(i32 %x) { +; CHECK-LABEL: @lshr_ctlz_zero_is_undef( +; CHECK-NEXT: ret i32 0 +; + %ct = call i32 @llvm.ctlz.i32(i32 %x, i1 true) + %sh = lshr i32 %ct, 5 + ret i32 %sh +} + +define i32 @lshr_cttz_zero_is_undef(i32 %x) { +; CHECK-LABEL: @lshr_cttz_zero_is_undef( +; CHECK-NEXT: ret i32 0 +; + %ct = call i32 @llvm.cttz.i32(i32 %x, i1 true) + %sh = lshr i32 %ct, 5 + ret i32 %sh +} + +define <2 x i8> @lshr_ctlz_zero_is_undef_splat_vec(<2 x i8> %x) { +; CHECK-LABEL: @lshr_ctlz_zero_is_undef_splat_vec( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %ct = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %x, i1 true) + %sh = lshr <2 x i8> %ct, <i8 3, i8 3> + ret <2 x i8> %sh +} + +define <2 x i8> @lshr_cttz_zero_is_undef_splat_vec(<2 x i8> %x) { +; CHECK-LABEL: @lshr_cttz_zero_is_undef_splat_vec( +; CHECK-NEXT: ret <2 x i8> zeroinitializer +; + %ct = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> %x, i1 true) + %sh = lshr <2 x i8> %ct, <i8 3, i8 3> + ret <2 x i8> %sh +} + diff --git a/llvm/test/Transforms/InstSimplify/shift.ll b/llvm/test/Transforms/InstSimplify/shift.ll new file mode 100644 index 00000000000..cbffd371853 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/shift.ll @@ -0,0 +1,239 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i47 @shl_by_0(i47 %A) { +; CHECK-LABEL: @shl_by_0( +; CHECK-NEXT: ret i47 [[A:%.*]] +; + %B = shl i47 %A, 0 + ret i47 %B +} + +define i41 @shl_0(i41 %X) { +; CHECK-LABEL: @shl_0( +; CHECK-NEXT: ret i41 0 +; + %B = shl i41 0, %X + ret i41 %B +} + +define <2 x i41> @shl_0_vec_undef_elt(<2 x i41> %X) { +; CHECK-LABEL: @shl_0_vec_undef_elt( +; CHECK-NEXT: ret <2 x i41> zeroinitializer +; + %B = shl <2 x i41> <i41 0, i41 undef>, %X + ret <2 x i41> %B +} + +define i41 @ashr_by_0(i41 %A) { +; CHECK-LABEL: @ashr_by_0( +; CHECK-NEXT: ret i41 [[A:%.*]] +; + %B = ashr i41 %A, 0 + ret i41 %B +} + +define i39 @ashr_0(i39 %X) { +; CHECK-LABEL: @ashr_0( +; CHECK-NEXT: ret i39 0 +; + %B = ashr i39 0, %X + ret i39 %B +} + +define <2 x i141> @ashr_0_vec_undef_elt(<2 x i141> %X) { +; CHECK-LABEL: @ashr_0_vec_undef_elt( +; CHECK-NEXT: ret <2 x i141> zeroinitializer +; + %B = shl <2 x i141> <i141 undef, i141 0>, %X + ret <2 x i141> %B +} + +define i55 @lshr_by_bitwidth(i55 %A) { +; CHECK-LABEL: @lshr_by_bitwidth( +; CHECK-NEXT: ret i55 undef +; + %B = lshr i55 %A, 55 + ret i55 %B +} + +define i32 @shl_by_bitwidth(i32 %A) { +; CHECK-LABEL: @shl_by_bitwidth( +; CHECK-NEXT: ret i32 undef +; + %B = shl i32 %A, 32 + ret i32 %B +} + +define <4 x i32> @lshr_by_bitwidth_splat(<4 x i32> %A) { +; CHECK-LABEL: @lshr_by_bitwidth_splat( +; CHECK-NEXT: ret <4 x i32> undef +; + %B = lshr <4 x i32> %A, <i32 32, i32 32, i32 32, i32 32> ;; shift all bits out + ret <4 x i32> %B +} + +define <4 x i32> @lshr_by_0_splat(<4 x i32> %A) { +; CHECK-LABEL: @lshr_by_0_splat( +; CHECK-NEXT: ret <4 x i32> [[A:%.*]] +; + %B = lshr <4 x i32> %A, zeroinitializer + ret <4 x i32> %B +} + +define <4 x i32> @shl_by_bitwidth_splat(<4 x i32> %A) { +; CHECK-LABEL: @shl_by_bitwidth_splat( +; CHECK-NEXT: ret <4 x i32> undef +; + %B = shl <4 x i32> %A, <i32 32, i32 32, i32 32, i32 32> ;; shift all bits out + ret <4 x i32> %B +} + +define i32 @ashr_undef() { +; CHECK-LABEL: @ashr_undef( +; CHECK-NEXT: ret i32 0 +; + %B = ashr i32 undef, 2 ;; top two bits must be equal, so not undef + ret i32 %B +} + +define i32 @ashr_undef_variable_shift_amount(i32 %A) { +; CHECK-LABEL: @ashr_undef_variable_shift_amount( +; CHECK-NEXT: ret i32 0 +; + %B = ashr i32 undef, %A ;; top %A bits must be equal, so not undef + ret i32 %B +} + +define i32 @ashr_all_ones(i32 %A) { +; CHECK-LABEL: @ashr_all_ones( +; CHECK-NEXT: ret i32 -1 +; + %B = ashr i32 -1, %A + ret i32 %B +} + +define <3 x i8> @ashr_all_ones_vec_with_undef_elts(<3 x i8> %x, <3 x i8> %y) { +; CHECK-LABEL: @ashr_all_ones_vec_with_undef_elts( +; CHECK-NEXT: ret <3 x i8> <i8 -1, i8 -1, i8 -1> +; + %sh = ashr <3 x i8> <i8 undef, i8 -1, i8 undef>, %y + ret <3 x i8> %sh +} + +define i8 @lshr_by_sext_bool(i1 %x, i8 %y) { +; CHECK-LABEL: @lshr_by_sext_bool( +; CHECK-NEXT: ret i8 [[Y:%.*]] +; + %s = sext i1 %x to i8 + %r = lshr i8 %y, %s + ret i8 %r +} + +define <2 x i8> @lshr_by_sext_bool_vec(<2 x i1> %x, <2 x i8> %y) { +; CHECK-LABEL: @lshr_by_sext_bool_vec( +; CHECK-NEXT: ret <2 x i8> [[Y:%.*]] +; + %s = sext <2 x i1> %x to <2 x i8> + %r = lshr <2 x i8> %y, %s + ret <2 x i8> %r +} + +define i8 @ashr_by_sext_bool(i1 %x, i8 %y) { +; CHECK-LABEL: @ashr_by_sext_bool( +; CHECK-NEXT: ret i8 [[Y:%.*]] +; + %s = sext i1 %x to i8 + %r = ashr i8 %y, %s + ret i8 %r +} + +define <2 x i8> @ashr_by_sext_bool_vec(<2 x i1> %x, <2 x i8> %y) { +; CHECK-LABEL: @ashr_by_sext_bool_vec( +; CHECK-NEXT: ret <2 x i8> [[Y:%.*]] +; + %s = sext <2 x i1> %x to <2 x i8> + %r = ashr <2 x i8> %y, %s + ret <2 x i8> %r +} + +define i8 @shl_by_sext_bool(i1 %x, i8 %y) { +; CHECK-LABEL: @shl_by_sext_bool( +; CHECK-NEXT: ret i8 [[Y:%.*]] +; + %s = sext i1 %x to i8 + %r = shl i8 %y, %s + ret i8 %r +} + +define <2 x i8> @shl_by_sext_bool_vec(<2 x i1> %x, <2 x i8> %y) { +; CHECK-LABEL: @shl_by_sext_bool_vec( +; CHECK-NEXT: ret <2 x i8> [[Y:%.*]] +; + %s = sext <2 x i1> %x to <2 x i8> + %r = shl <2 x i8> %y, %s + ret <2 x i8> %r +} + +define i64 @shl_or_shr(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_or_shr( +; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[A:%.*]] to i64 +; CHECK-NEXT: ret i64 [[TMP1]] +; + %tmp1 = zext i32 %a to i64 + %tmp2 = zext i32 %b to i64 + %tmp3 = shl nuw i64 %tmp1, 32 + %tmp4 = or i64 %tmp2, %tmp3 + %tmp5 = lshr i64 %tmp4, 32 + ret i64 %tmp5 +} + +; Since shift count of shl is smaller than the size of %b, OR cannot be eliminated. +define i64 @shl_or_shr2(i32 %a, i32 %b) { +; CHECK-LABEL: @shl_or_shr2( +; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[A:%.*]] to i64 +; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[B:%.*]] to i64 +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw i64 [[TMP1]], 31 +; CHECK-NEXT: [[TMP4:%.*]] = or i64 [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = lshr i64 [[TMP4]], 31 +; CHECK-NEXT: ret i64 [[TMP5]] +; + %tmp1 = zext i32 %a to i64 + %tmp2 = zext i32 %b to i64 + %tmp3 = shl nuw i64 %tmp1, 31 + %tmp4 = or i64 %tmp2, %tmp3 + %tmp5 = lshr i64 %tmp4, 31 + ret i64 %tmp5 +} + +; Unit test for vector integer +define <2 x i64> @shl_or_shr1v(<2 x i32> %a, <2 x i32> %b) { +; CHECK-LABEL: @shl_or_shr1v( +; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i32> [[A:%.*]] to <2 x i64> +; CHECK-NEXT: ret <2 x i64> [[TMP1]] +; + %tmp1 = zext <2 x i32> %a to <2 x i64> + %tmp2 = zext <2 x i32> %b to <2 x i64> + %tmp3 = shl nuw <2 x i64> %tmp1, <i64 32, i64 32> + %tmp4 = or <2 x i64> %tmp3, %tmp2 + %tmp5 = lshr <2 x i64> %tmp4, <i64 32, i64 32> + ret <2 x i64> %tmp5 +} + +; Negative unit test for vector integer +define <2 x i64> @shl_or_shr2v(<2 x i32> %a, <2 x i32> %b) { +; CHECK-LABEL: @shl_or_shr2v( +; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i32> [[A:%.*]] to <2 x i64> +; CHECK-NEXT: [[TMP2:%.*]] = zext <2 x i32> [[B:%.*]] to <2 x i64> +; CHECK-NEXT: [[TMP3:%.*]] = shl nuw <2 x i64> [[TMP1]], <i64 31, i64 31> +; CHECK-NEXT: [[TMP4:%.*]] = or <2 x i64> [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = lshr <2 x i64> [[TMP4]], <i64 31, i64 31> +; CHECK-NEXT: ret <2 x i64> [[TMP5]] +; + %tmp1 = zext <2 x i32> %a to <2 x i64> + %tmp2 = zext <2 x i32> %b to <2 x i64> + %tmp3 = shl nuw <2 x i64> %tmp1, <i64 31, i64 31> + %tmp4 = or <2 x i64> %tmp2, %tmp3 + %tmp5 = lshr <2 x i64> %tmp4, <i64 31, i64 31> + ret <2 x i64> %tmp5 +} diff --git a/llvm/test/Transforms/InstSimplify/shr-nop.ll b/llvm/test/Transforms/InstSimplify/shr-nop.ll new file mode 100644 index 00000000000..9b0f4e9fe50 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/shr-nop.ll @@ -0,0 +1,431 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @foo(i32 %x) { +; CHECK-LABEL: @foo( +; CHECK-NEXT: [[O:%.*]] = and i32 %x, 1 +; CHECK-NEXT: [[N:%.*]] = add i32 [[O]], -1 +; CHECK-NEXT: ret i32 [[N]] +; + %o = and i32 %x, 1 + %n = add i32 %o, -1 + %t = ashr i32 %n, 17 + ret i32 %t +} + +define i1 @exact_lshr_eq_both_zero(i8 %a) { +; CHECK-LABEL: @exact_lshr_eq_both_zero( +; CHECK-NEXT: ret i1 true +; + %shr = lshr exact i8 0, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @exact_ashr_eq_both_zero(i8 %a) { +; CHECK-LABEL: @exact_ashr_eq_both_zero( +; CHECK-NEXT: ret i1 true +; + %shr = ashr exact i8 0, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_ashr_eq_both_zero(i8 %a) { +; CHECK-LABEL: @nonexact_ashr_eq_both_zero( +; CHECK-NEXT: ret i1 true +; + %shr = ashr i8 0, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @exact_lshr_ne_both_zero(i8 %a) { +; CHECK-LABEL: @exact_lshr_ne_both_zero( +; CHECK-NEXT: ret i1 false +; + %shr = lshr exact i8 0, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @exact_ashr_ne_both_zero(i8 %a) { +; CHECK-LABEL: @exact_ashr_ne_both_zero( +; CHECK-NEXT: ret i1 false +; + %shr = ashr exact i8 0, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_lshr_ne_both_zero(i8 %a) { +; CHECK-LABEL: @nonexact_lshr_ne_both_zero( +; CHECK-NEXT: ret i1 false +; + %shr = lshr i8 0, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_ashr_ne_both_zero(i8 %a) { +; CHECK-LABEL: @nonexact_ashr_ne_both_zero( +; CHECK-NEXT: ret i1 false +; + %shr = ashr i8 0, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @exact_lshr_eq_last_zero(i8 %a) { +; CHECK-LABEL: @exact_lshr_eq_last_zero( +; CHECK-NEXT: ret i1 false +; + %shr = lshr exact i8 128, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @exact_ashr_eq_last_zero(i8 %a) { +; CHECK-LABEL: @exact_ashr_eq_last_zero( +; CHECK-NEXT: ret i1 false +; + %shr = ashr exact i8 -128, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_lshr_eq_both_zero(i8 %a) { +; CHECK-LABEL: @nonexact_lshr_eq_both_zero( +; CHECK-NEXT: ret i1 true +; + %shr = lshr i8 0, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @exact_lshr_ne_last_zero(i8 %a) { +; CHECK-LABEL: @exact_lshr_ne_last_zero( +; CHECK-NEXT: ret i1 true +; + %shr = lshr exact i8 128, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @exact_ashr_ne_last_zero(i8 %a) { +; CHECK-LABEL: @exact_ashr_ne_last_zero( +; CHECK-NEXT: ret i1 true +; + %shr = ashr exact i8 -128, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_lshr_eq_last_zero(i8 %a) { +; CHECK-LABEL: @nonexact_lshr_eq_last_zero( +; CHECK-NEXT: ret i1 false +; + %shr = lshr i8 128, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_ashr_eq_last_zero(i8 %a) { +; CHECK-LABEL: @nonexact_ashr_eq_last_zero( +; CHECK-NEXT: ret i1 false +; + %shr = ashr i8 -128, %a + %cmp = icmp eq i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_lshr_ne_last_zero(i8 %a) { +; CHECK-LABEL: @nonexact_lshr_ne_last_zero( +; CHECK-NEXT: ret i1 true +; + %shr = lshr i8 128, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @nonexact_ashr_ne_last_zero(i8 %a) { +; CHECK-LABEL: @nonexact_ashr_ne_last_zero( +; CHECK-NEXT: ret i1 true +; + %shr = ashr i8 -128, %a + %cmp = icmp ne i8 %shr, 0 + ret i1 %cmp +} + +define i1 @lshr_eq_first_zero(i8 %a) { +; CHECK-LABEL: @lshr_eq_first_zero( +; CHECK-NEXT: ret i1 false +; + %shr = lshr i8 0, %a + %cmp = icmp eq i8 %shr, 2 + ret i1 %cmp +} + +define i1 @ashr_eq_first_zero(i8 %a) { +; CHECK-LABEL: @ashr_eq_first_zero( +; CHECK-NEXT: ret i1 false +; + %shr = ashr i8 0, %a + %cmp = icmp eq i8 %shr, 2 + ret i1 %cmp +} + +define i1 @lshr_ne_first_zero(i8 %a) { +; CHECK-LABEL: @lshr_ne_first_zero( +; CHECK-NEXT: ret i1 true +; + %shr = lshr i8 0, %a + %cmp = icmp ne i8 %shr, 2 + ret i1 %cmp +} + +define i1 @ashr_ne_first_zero(i8 %a) { +; CHECK-LABEL: @ashr_ne_first_zero( +; CHECK-NEXT: ret i1 true +; + %shr = ashr i8 0, %a + %cmp = icmp ne i8 %shr, 2 + ret i1 %cmp +} + +define i1 @ashr_eq_both_minus1(i8 %a) { +; CHECK-LABEL: @ashr_eq_both_minus1( +; CHECK-NEXT: ret i1 true +; + %shr = ashr i8 -1, %a + %cmp = icmp eq i8 %shr, -1 + ret i1 %cmp +} + +define i1 @ashr_ne_both_minus1(i8 %a) { +; CHECK-LABEL: @ashr_ne_both_minus1( +; CHECK-NEXT: ret i1 false +; + %shr = ashr i8 -1, %a + %cmp = icmp ne i8 %shr, -1 + ret i1 %cmp +} + +define i1 @exact_ashr_eq_both_minus1(i8 %a) { +; CHECK-LABEL: @exact_ashr_eq_both_minus1( +; CHECK-NEXT: ret i1 true +; + %shr = ashr exact i8 -1, %a + %cmp = icmp eq i8 %shr, -1 + ret i1 %cmp +} + +define i1 @exact_ashr_ne_both_minus1(i8 %a) { +; CHECK-LABEL: @exact_ashr_ne_both_minus1( +; CHECK-NEXT: ret i1 false +; + %shr = ashr exact i8 -1, %a + %cmp = icmp ne i8 %shr, -1 + ret i1 %cmp +} + +define i1 @exact_ashr_eq_opposite_msb(i8 %a) { +; CHECK-LABEL: @exact_ashr_eq_opposite_msb( +; CHECK-NEXT: ret i1 false +; + %shr = ashr exact i8 -128, %a + %cmp = icmp eq i8 %shr, 1 + ret i1 %cmp +} + +define i1 @exact_ashr_eq_noexactlog(i8 %a) { +; CHECK-LABEL: @exact_ashr_eq_noexactlog( +; CHECK-NEXT: ret i1 false +; + %shr = ashr exact i8 -90, %a + %cmp = icmp eq i8 %shr, -30 + ret i1 %cmp +} + +define i1 @exact_ashr_ne_opposite_msb(i8 %a) { +; CHECK-LABEL: @exact_ashr_ne_opposite_msb( +; CHECK-NEXT: ret i1 true +; + %shr = ashr exact i8 -128, %a + %cmp = icmp ne i8 %shr, 1 + ret i1 %cmp +} + +define i1 @ashr_eq_opposite_msb(i8 %a) { +; CHECK-LABEL: @ashr_eq_opposite_msb( +; CHECK-NEXT: ret i1 false +; + %shr = ashr i8 -128, %a + %cmp = icmp eq i8 %shr, 1 + ret i1 %cmp +} + +define i1 @ashr_ne_opposite_msb(i8 %a) { +; CHECK-LABEL: @ashr_ne_opposite_msb( +; CHECK-NEXT: ret i1 true +; + %shr = ashr i8 -128, %a + %cmp = icmp ne i8 %shr, 1 + ret i1 %cmp +} + +define i1 @exact_ashr_eq_shift_gt(i8 %a) { +; CHECK-LABEL: @exact_ashr_eq_shift_gt( +; CHECK-NEXT: ret i1 false +; + %shr = ashr exact i8 -2, %a + %cmp = icmp eq i8 %shr, -8 + ret i1 %cmp +} + +define i1 @exact_ashr_ne_shift_gt(i8 %a) { +; CHECK-LABEL: @exact_ashr_ne_shift_gt( +; CHECK-NEXT: ret i1 true +; + %shr = ashr exact i8 -2, %a + %cmp = icmp ne i8 %shr, -8 + ret i1 %cmp +} + +define i1 @nonexact_ashr_eq_shift_gt(i8 %a) { +; CHECK-LABEL: @nonexact_ashr_eq_shift_gt( +; CHECK-NEXT: ret i1 false +; + %shr = ashr i8 -2, %a + %cmp = icmp eq i8 %shr, -8 + ret i1 %cmp +} + +define i1 @nonexact_ashr_ne_shift_gt(i8 %a) { +; CHECK-LABEL: @nonexact_ashr_ne_shift_gt( +; CHECK-NEXT: ret i1 true +; + %shr = ashr i8 -2, %a + %cmp = icmp ne i8 %shr, -8 + ret i1 %cmp +} + +define i1 @exact_lshr_eq_shift_gt(i8 %a) { +; CHECK-LABEL: @exact_lshr_eq_shift_gt( +; CHECK-NEXT: ret i1 false +; + %shr = lshr exact i8 2, %a + %cmp = icmp eq i8 %shr, 8 + ret i1 %cmp +} + +define i1 @exact_lshr_ne_shift_gt(i8 %a) { +; CHECK-LABEL: @exact_lshr_ne_shift_gt( +; CHECK-NEXT: ret i1 true +; + %shr = lshr exact i8 2, %a + %cmp = icmp ne i8 %shr, 8 + ret i1 %cmp +} + +define i1 @nonexact_lshr_eq_shift_gt(i8 %a) { +; CHECK-LABEL: @nonexact_lshr_eq_shift_gt( +; CHECK-NEXT: ret i1 false +; + %shr = lshr i8 2, %a + %cmp = icmp eq i8 %shr, 8 + ret i1 %cmp +} + +define i1 @nonexact_lshr_ne_shift_gt(i8 %a) { +; CHECK-LABEL: @nonexact_lshr_ne_shift_gt( +; CHECK-NEXT: ret i1 true +; + %shr = ashr i8 2, %a + %cmp = icmp ne i8 %shr, 8 + ret i1 %cmp +} + +define i1 @exact_ashr_ne_noexactlog(i8 %a) { +; CHECK-LABEL: @exact_ashr_ne_noexactlog( +; CHECK-NEXT: ret i1 true +; + %shr = ashr exact i8 -90, %a + %cmp = icmp ne i8 %shr, -30 + ret i1 %cmp +} + +define i1 @exact_lshr_eq_noexactlog(i8 %a) { +; CHECK-LABEL: @exact_lshr_eq_noexactlog( +; CHECK-NEXT: ret i1 false +; + %shr = lshr exact i8 90, %a + %cmp = icmp eq i8 %shr, 30 + ret i1 %cmp +} + +define i1 @exact_lshr_ne_noexactlog(i8 %a) { +; CHECK-LABEL: @exact_lshr_ne_noexactlog( +; CHECK-NEXT: ret i1 true +; + %shr = lshr exact i8 90, %a + %cmp = icmp ne i8 %shr, 30 + ret i1 %cmp +} + +define i32 @exact_lshr_lowbit(i32 %shiftval) { +; CHECK-LABEL: @exact_lshr_lowbit( +; CHECK-NEXT: ret i32 7 +; + %shr = lshr exact i32 7, %shiftval + ret i32 %shr +} + +define i32 @exact_ashr_lowbit(i32 %shiftval) { +; CHECK-LABEL: @exact_ashr_lowbit( +; CHECK-NEXT: ret i32 7 +; + %shr = ashr exact i32 7, %shiftval + ret i32 %shr +} + +define i32 @ashr_zero(i32 %shiftval) { +; CHECK-LABEL: @ashr_zero( +; CHECK-NEXT: ret i32 0 +; + %shr = ashr i32 0, %shiftval + ret i32 %shr +} + +define i257 @ashr_minus1(i257 %shiftval) { +; CHECK-LABEL: @ashr_minus1( +; CHECK-NEXT: ret i257 -1 +; + %shr = ashr i257 -1, %shiftval + ret i257 %shr +} + +define <2 x i4097> @ashr_zero_vec(<2 x i4097> %shiftval) { +; CHECK-LABEL: @ashr_zero_vec( +; CHECK-NEXT: ret <2 x i4097> zeroinitializer +; + %shr = ashr <2 x i4097> zeroinitializer, %shiftval + ret <2 x i4097> %shr +} + +define <2 x i64> @ashr_minus1_vec(<2 x i64> %shiftval) { +; CHECK-LABEL: @ashr_minus1_vec( +; CHECK-NEXT: ret <2 x i64> <i64 -1, i64 -1> +; + %shr = ashr <2 x i64> <i64 -1, i64 -1>, %shiftval + ret <2 x i64> %shr +} + +define <2 x i4> @ashr_zero_minus1_vec(<2 x i4> %shiftval) { +; CHECK-LABEL: @ashr_zero_minus1_vec( +; CHECK-NEXT: ret <2 x i4> <i4 0, i4 -1> +; + %shr = ashr <2 x i4> <i4 0, i4 -1>, %shiftval + ret <2 x i4> %shr +} + diff --git a/llvm/test/Transforms/InstSimplify/shr-scalar-vector-consistency.ll b/llvm/test/Transforms/InstSimplify/shr-scalar-vector-consistency.ll new file mode 100644 index 00000000000..90725a153a2 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/shr-scalar-vector-consistency.ll @@ -0,0 +1,25 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; This tests checks optimization consistency for scalar and vector code. +; If m_Zero() is able to match a vector undef, but not a scalar undef, +; the two cases will simplify differently. + +define i32 @test_scalar(i32 %a, i1 %b) { +; CHECK-LABEL: @test_scalar( +; CHECK-NEXT: ret i32 undef +; + %c = sext i1 %b to i32 + %d = ashr i32 undef, %c + ret i32 %d +} + +define <2 x i32> @test_vector(<2 x i32> %a, <2 x i1> %b) { +; CHECK-LABEL: @test_vector( +; CHECK-NEXT: ret <2 x i32> undef +; + %c = sext <2 x i1> %b to <2 x i32> + %d = ashr <2 x i32> undef, %c + ret <2 x i32> %d +} + diff --git a/llvm/test/Transforms/InstSimplify/shufflevector.ll b/llvm/test/Transforms/InstSimplify/shufflevector.ll new file mode 100644 index 00000000000..cc49ae3554c --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/shufflevector.ll @@ -0,0 +1,249 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define <4 x i32> @const_folding(<4 x i32> %x) { +; CHECK-LABEL: @const_folding( +; CHECK-NEXT: ret <4 x i32> zeroinitializer +; + %shuf = shufflevector <4 x i32> %x, <4 x i32> zeroinitializer, <4 x i32> <i32 5, i32 4, i32 5, i32 4> + ret <4 x i32> %shuf +} + +define <4 x i32> @const_folding1(<4 x i32> %x) { +; CHECK-LABEL: @const_folding1( +; CHECK-NEXT: ret <4 x i32> <i32 5, i32 5, i32 5, i32 5> +; + %shuf = shufflevector <4 x i32> <i32 5, i32 4, i32 5, i32 4>, <4 x i32> %x, <4 x i32> zeroinitializer + ret <4 x i32> %shuf +} + +define <4 x i32> @const_folding_negative(<3 x i32> %x) { +; CHECK-LABEL: @const_folding_negative( +; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <3 x i32> [[X:%.*]], <3 x i32> zeroinitializer, <4 x i32> <i32 2, i32 4, i32 5, i32 4> +; CHECK-NEXT: ret <4 x i32> [[SHUF]] +; + %shuf = shufflevector <3 x i32> %x, <3 x i32> zeroinitializer, <4 x i32> <i32 2, i32 4, i32 5, i32 4> + ret <4 x i32> %shuf +} + +define <4 x i32> @splat_operand(<4 x i32> %x) { +; CHECK-LABEL: @splat_operand( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer +; CHECK-NEXT: ret <4 x i32> [[SPLAT]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> zeroinitializer + %shuf = shufflevector <4 x i32> %splat, <4 x i32> undef, <4 x i32> <i32 0, i32 3, i32 2, i32 1> + ret <4 x i32> %shuf +} + +define <4 x i32> @splat_operand1(<4 x i32> %x, <4 x i32> %y) { +; CHECK-LABEL: @splat_operand1( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> zeroinitializer +; CHECK-NEXT: ret <4 x i32> [[SPLAT]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> zeroinitializer + %shuf = shufflevector <4 x i32> %splat, <4 x i32> undef, <4 x i32> <i32 0, i32 3, i32 2, i32 1> + ret <4 x i32> %shuf +} + +define <4 x i32> @splat_operand2(<4 x i32> %x, <4 x i32> %y) { +; CHECK-LABEL: @splat_operand2( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer +; CHECK-NEXT: ret <4 x i32> [[SPLAT]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> zeroinitializer + %shuf = shufflevector <4 x i32> %splat, <4 x i32> %y, <4 x i32> <i32 0, i32 3, i32 2, i32 1> + ret <4 x i32> %shuf +} + +define <4 x i32> @splat_operand3(<4 x i32> %x) { +; CHECK-LABEL: @splat_operand3( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer +; CHECK-NEXT: ret <4 x i32> [[SPLAT]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> zeroinitializer + %shuf = shufflevector <4 x i32> zeroinitializer, <4 x i32> %splat, <4 x i32> <i32 7, i32 6, i32 5, i32 5> + ret <4 x i32> %shuf +} + +define <8 x i32> @splat_operand_negative(<4 x i32> %x) { +; CHECK-LABEL: @splat_operand_negative( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer +; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SPLAT]], <4 x i32> undef, <8 x i32> <i32 0, i32 3, i32 2, i32 1, i32 undef, i32 undef, i32 undef, i32 undef> +; CHECK-NEXT: ret <8 x i32> [[SHUF]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> zeroinitializer + %shuf = shufflevector <4 x i32> %splat, <4 x i32> undef, <8 x i32> <i32 0, i32 3, i32 2, i32 1, i32 undef, i32 undef, i32 undef, i32 undef> + ret <8 x i32> %shuf +} + +define <4 x i32> @splat_operand_negative2(<4 x i32> %x, <4 x i32> %y) { +; CHECK-LABEL: @splat_operand_negative2( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer +; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SPLAT]], <4 x i32> [[Y:%.*]], <4 x i32> <i32 0, i32 3, i32 4, i32 1> +; CHECK-NEXT: ret <4 x i32> [[SHUF]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> zeroinitializer + %shuf = shufflevector <4 x i32> %splat, <4 x i32> %y, <4 x i32> <i32 0, i32 3, i32 4, i32 1> + ret <4 x i32> %shuf +} + +define <4 x i32> @splat_operand_negative3(<4 x i32> %x, <4 x i32> %y) { +; CHECK-LABEL: @splat_operand_negative3( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> zeroinitializer +; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[Y:%.*]], <4 x i32> [[SPLAT]], <4 x i32> <i32 0, i32 3, i32 4, i32 1> +; CHECK-NEXT: ret <4 x i32> [[SHUF]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> zeroinitializer + %shuf = shufflevector <4 x i32> %y, <4 x i32> %splat, <4 x i32> <i32 0, i32 3, i32 4, i32 1> + ret <4 x i32> %shuf +} + +define <4 x i32> @splat_operand_negative4(<4 x i32> %x) { +; CHECK-LABEL: @splat_operand_negative4( +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> <i32 2, i32 undef, i32 2, i32 undef> +; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SPLAT]], <4 x i32> undef, <4 x i32> <i32 0, i32 2, i32 undef, i32 undef> +; CHECK-NEXT: ret <4 x i32> [[SHUF]] +; + %splat = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 2, i32 undef, i32 2, i32 undef> + %shuf = shufflevector <4 x i32> %splat, <4 x i32> undef, <4 x i32> <i32 0, i32 2, i32 undef, i32 undef> + ret <4 x i32> %shuf +} + +define <4 x i32> @undef_mask(<4 x i32> %x) { +; CHECK-LABEL: @undef_mask( +; CHECK-NEXT: ret <4 x i32> undef +; + %shuf = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> undef + ret <4 x i32> %shuf +} + +define <4 x i32> @undef_mask_1(<4 x i32> %x, <4 x i32> %y) { +; CHECK-LABEL: @undef_mask_1( +; CHECK-NEXT: ret <4 x i32> undef +; + %shuf = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> undef + ret <4 x i32> %shuf +} + +define <4 x i32> @identity_mask_0(<4 x i32> %x) { +; CHECK-LABEL: @identity_mask_0( +; CHECK-NEXT: ret <4 x i32> [[X:%.*]] +; + %shuf = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + ret <4 x i32> %shuf +} + +define <4 x i32> @identity_mask_1(<4 x i32> %x) { +; CHECK-LABEL: @identity_mask_1( +; CHECK-NEXT: ret <4 x i32> [[X:%.*]] +; + %shuf = shufflevector <4 x i32> undef, <4 x i32> %x, <4 x i32> <i32 4, i32 5, i32 6, i32 7> + ret <4 x i32> %shuf +} + +define <4 x i32> @pseudo_identity_mask(<4 x i32> %x) { +; CHECK-LABEL: @pseudo_identity_mask( +; CHECK-NEXT: ret <4 x i32> [[X:%.*]] +; + %shuf = shufflevector <4 x i32> %x, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 2, i32 7> + ret <4 x i32> %shuf +} + +define <4 x i32> @not_identity_mask(<4 x i32> %x) { +; CHECK-LABEL: @not_identity_mask( +; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> [[X]], <4 x i32> <i32 0, i32 1, i32 2, i32 6> +; CHECK-NEXT: ret <4 x i32> [[SHUF]] +; + %shuf = shufflevector <4 x i32> %x, <4 x i32> %x, <4 x i32> <i32 0, i32 1, i32 2, i32 6> + ret <4 x i32> %shuf +} + +; TODO: Should we simplify if the mask has an undef element? + +define <4 x i32> @possible_identity_mask(<4 x i32> %x) { +; CHECK-LABEL: @possible_identity_mask( +; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef> +; CHECK-NEXT: ret <4 x i32> [[SHUF]] +; + %shuf = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef> + ret <4 x i32> %shuf +} + +define <4 x i32> @const_operand(<4 x i32> %x) { +; CHECK-LABEL: @const_operand( +; CHECK-NEXT: ret <4 x i32> <i32 42, i32 45, i32 44, i32 43> +; + %shuf = shufflevector <4 x i32> <i32 42, i32 43, i32 44, i32 45>, <4 x i32> %x, <4 x i32> <i32 0, i32 3, i32 2, i32 1> + ret <4 x i32> %shuf +} + +define <4 x i32> @merge(<4 x i32> %x) { +; CHECK-LABEL: @merge( +; CHECK-NEXT: ret <4 x i32> [[X:%.*]] +; + %lower = shufflevector <4 x i32> %x, <4 x i32> undef, <2 x i32> <i32 1, i32 0> + %upper = shufflevector <4 x i32> %x, <4 x i32> undef, <2 x i32> <i32 2, i32 3> + %merged = shufflevector <2 x i32> %upper, <2 x i32> %lower, <4 x i32> <i32 3, i32 2, i32 0, i32 1> + ret <4 x i32> %merged +} + +; This crosses lanes from the source op. + +define <4 x i32> @not_merge(<4 x i32> %x) { +; CHECK-LABEL: @not_merge( +; CHECK-NEXT: [[L:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <2 x i32> <i32 0, i32 1> +; CHECK-NEXT: [[U:%.*]] = shufflevector <4 x i32> [[X]], <4 x i32> undef, <2 x i32> <i32 2, i32 3> +; CHECK-NEXT: [[MERGED:%.*]] = shufflevector <2 x i32> [[U]], <2 x i32> [[L]], <4 x i32> <i32 3, i32 2, i32 0, i32 1> +; CHECK-NEXT: ret <4 x i32> [[MERGED]] +; + %l = shufflevector <4 x i32> %x, <4 x i32> undef, <2 x i32> <i32 0, i32 1> + %u = shufflevector <4 x i32> %x, <4 x i32> undef, <2 x i32> <i32 2, i32 3> + %merged = shufflevector <2 x i32> %u, <2 x i32> %l, <4 x i32> <i32 3, i32 2, i32 0, i32 1> + ret <4 x i32> %merged +} + +define <8 x double> @extract_and_concat(<8 x double> %x) { +; CHECK-LABEL: @extract_and_concat( +; CHECK-NEXT: ret <8 x double> [[X:%.*]] +; + %s1 = shufflevector <8 x double> %x, <8 x double> undef, <2 x i32> <i32 0, i32 1> + %s2 = shufflevector <8 x double> %x, <8 x double> undef, <2 x i32> <i32 2, i32 3> + %s3 = shufflevector <8 x double> %x, <8 x double> undef, <2 x i32> <i32 4, i32 5> + %s4 = shufflevector <8 x double> %x, <8 x double> undef, <2 x i32> <i32 6, i32 7> + %s5 = shufflevector <2 x double> %s1, <2 x double> %s2, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + %s6 = shufflevector <2 x double> %s3, <2 x double> %s4, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + %s7 = shufflevector <4 x double> %s5, <4 x double> %s6, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> + ret <8 x double> %s7 +} + +; This case has intermediate lane crossings. + +define <8 x i64> @PR30630(<8 x i64> %x) { +; CHECK-LABEL: @PR30630( +; CHECK-NEXT: ret <8 x i64> [[X:%.*]] +; + %s1 = shufflevector <8 x i64> %x, <8 x i64> undef, <2 x i32> <i32 0, i32 4> + %s2 = shufflevector <8 x i64> %x, <8 x i64> undef, <2 x i32> <i32 1, i32 5> + %s3 = shufflevector <8 x i64> %x, <8 x i64> undef, <2 x i32> <i32 2, i32 6> + %s4 = shufflevector <8 x i64> %x, <8 x i64> undef, <2 x i32> <i32 3, i32 7> + %s5 = shufflevector <2 x i64> %s1, <2 x i64> %s2, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + %s6 = shufflevector <2 x i64> %s3, <2 x i64> %s4, <4 x i32> <i32 0, i32 1, i32 2, i32 3> + %s7 = shufflevector <4 x i64> %s5, <4 x i64> %s6, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 1, i32 3, i32 5, i32 7> + ret <8 x i64> %s7 +} + +; This case covers internal canonicalization of shuffles with one constant input vector. + +;FIXME: Another issue exposed here, this whole function could be simplified to: +; ret <2 x float> zeroinitializer +define <2 x float> @PR32872(<2 x float> %x) { +; CHECK-LABEL: @PR32872( +; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x float> [[X:%.*]], <2 x float> zeroinitializer, <4 x i32> <i32 2, i32 2, i32 0, i32 1> +; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <4 x float> zeroinitializer, <4 x float> [[TMP1]], <2 x i32> <i32 4, i32 5> +; CHECK-NEXT: ret <2 x float> [[TMP4]] +; + %tmp1 = shufflevector <2 x float> %x, <2 x float> zeroinitializer, <4 x i32> <i32 2, i32 2, i32 0, i32 1> + %tmp4 = shufflevector <4 x float> zeroinitializer, <4 x float> %tmp1, <2 x i32> <i32 4, i32 5> + ret <2 x float> %tmp4 +} diff --git a/llvm/test/Transforms/InstSimplify/signed-div-rem.ll b/llvm/test/Transforms/InstSimplify/signed-div-rem.ll new file mode 100644 index 00000000000..5e8388ae3ba --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/signed-div-rem.ll @@ -0,0 +1,354 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @sdiv_sext_big_divisor(i8 %x) { +; CHECK-LABEL: @sdiv_sext_big_divisor( +; CHECK-NEXT: ret i32 0 +; + %conv = sext i8 %x to i32 + %div = sdiv i32 %conv, 129 + ret i32 %div +} + +define i32 @not_sdiv_sext_big_divisor(i8 %x) { +; CHECK-LABEL: @not_sdiv_sext_big_divisor( +; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], 128 +; CHECK-NEXT: ret i32 [[DIV]] +; + %conv = sext i8 %x to i32 + %div = sdiv i32 %conv, 128 + ret i32 %div +} + +define i32 @sdiv_sext_small_divisor(i8 %x) { +; CHECK-LABEL: @sdiv_sext_small_divisor( +; CHECK-NEXT: ret i32 0 +; + %conv = sext i8 %x to i32 + %div = sdiv i32 %conv, -129 + ret i32 %div +} + +define i32 @not_sdiv_sext_small_divisor(i8 %x) { +; CHECK-LABEL: @not_sdiv_sext_small_divisor( +; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], -128 +; CHECK-NEXT: ret i32 [[DIV]] +; + %conv = sext i8 %x to i32 + %div = sdiv i32 %conv, -128 + ret i32 %div +} + +define i32 @sdiv_zext_big_divisor(i8 %x) { +; CHECK-LABEL: @sdiv_zext_big_divisor( +; CHECK-NEXT: ret i32 0 +; + %conv = zext i8 %x to i32 + %div = sdiv i32 %conv, 256 + ret i32 %div +} + +define i32 @not_sdiv_zext_big_divisor(i8 %x) { +; CHECK-LABEL: @not_sdiv_zext_big_divisor( +; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], 255 +; CHECK-NEXT: ret i32 [[DIV]] +; + %conv = zext i8 %x to i32 + %div = sdiv i32 %conv, 255 + ret i32 %div +} + +define i32 @sdiv_zext_small_divisor(i8 %x) { +; CHECK-LABEL: @sdiv_zext_small_divisor( +; CHECK-NEXT: ret i32 0 +; + %conv = zext i8 %x to i32 + %div = sdiv i32 %conv, -256 + ret i32 %div +} + +define i32 @not_sdiv_zext_small_divisor(i8 %x) { +; CHECK-LABEL: @not_sdiv_zext_small_divisor( +; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], -255 +; CHECK-NEXT: ret i32 [[DIV]] +; + %conv = zext i8 %x to i32 + %div = sdiv i32 %conv, -255 + ret i32 %div +} + +define i32 @sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @sdiv_dividend_known_smaller_than_pos_divisor_clear_bits( +; CHECK-NEXT: ret i32 0 +; + %and = and i32 %x, 253 + %div = sdiv i32 %and, 254 + ret i32 %div +} + +define i32 @not_sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_pos_divisor_clear_bits( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[AND]], 253 +; CHECK-NEXT: ret i32 [[DIV]] +; + %and = and i32 %x, 253 + %div = sdiv i32 %and, 253 + ret i32 %div +} + +define i32 @sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @sdiv_dividend_known_smaller_than_neg_divisor_clear_bits( +; CHECK-NEXT: ret i32 0 +; + %and = and i32 %x, 253 + %div = sdiv i32 %and, -254 + ret i32 %div +} + +define i32 @not_sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_neg_divisor_clear_bits( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[AND]], -253 +; CHECK-NEXT: ret i32 [[DIV]] +; + %and = and i32 %x, 253 + %div = sdiv i32 %and, -253 + ret i32 %div +} + +define i32 @sdiv_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @sdiv_dividend_known_smaller_than_pos_divisor_set_bits( +; CHECK-NEXT: ret i32 0 +; + %or = or i32 %x, -253 + %div = sdiv i32 %or, 254 + ret i32 %div +} + +define i32 @not_sdiv_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_pos_divisor_set_bits( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[OR]], 253 +; CHECK-NEXT: ret i32 [[DIV]] +; + %or = or i32 %x, -253 + %div = sdiv i32 %or, 253 + ret i32 %div +} + +define i32 @sdiv_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @sdiv_dividend_known_smaller_than_neg_divisor_set_bits( +; CHECK-NEXT: ret i32 0 +; + %or = or i32 %x, -253 + %div = sdiv i32 %or, -254 + ret i32 %div +} + +define i32 @not_sdiv_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_neg_divisor_set_bits( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[OR]], -253 +; CHECK-NEXT: ret i32 [[DIV]] +; + %or = or i32 %x, -253 + %div = sdiv i32 %or, -253 + ret i32 %div +} + +define i32 @srem_sext_big_divisor(i8 %x) { +; CHECK-LABEL: @srem_sext_big_divisor( +; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32 +; CHECK-NEXT: ret i32 [[CONV]] +; + %conv = sext i8 %x to i32 + %rem = srem i32 %conv, 129 + ret i32 %rem +} + +define i32 @not_srem_sext_big_divisor(i8 %x) { +; CHECK-LABEL: @not_srem_sext_big_divisor( +; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], 128 +; CHECK-NEXT: ret i32 [[REM]] +; + %conv = sext i8 %x to i32 + %rem = srem i32 %conv, 128 + ret i32 %rem +} + +define i32 @srem_sext_small_divisor(i8 %x) { +; CHECK-LABEL: @srem_sext_small_divisor( +; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32 +; CHECK-NEXT: ret i32 [[CONV]] +; + %conv = sext i8 %x to i32 + %rem = srem i32 %conv, -129 + ret i32 %rem +} + +define i32 @not_srem_sext_small_divisor(i8 %x) { +; CHECK-LABEL: @not_srem_sext_small_divisor( +; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], -128 +; CHECK-NEXT: ret i32 [[REM]] +; + %conv = sext i8 %x to i32 + %rem = srem i32 %conv, -128 + ret i32 %rem +} + +define i32 @srem_zext_big_divisor(i8 %x) { +; CHECK-LABEL: @srem_zext_big_divisor( +; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32 +; CHECK-NEXT: ret i32 [[CONV]] +; + %conv = zext i8 %x to i32 + %rem = srem i32 %conv, 256 + ret i32 %rem +} + +define i32 @not_srem_zext_big_divisor(i8 %x) { +; CHECK-LABEL: @not_srem_zext_big_divisor( +; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], 255 +; CHECK-NEXT: ret i32 [[REM]] +; + %conv = zext i8 %x to i32 + %rem = srem i32 %conv, 255 + ret i32 %rem +} + +define i32 @srem_zext_small_divisor(i8 %x) { +; CHECK-LABEL: @srem_zext_small_divisor( +; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32 +; CHECK-NEXT: ret i32 [[CONV]] +; + %conv = zext i8 %x to i32 + %rem = srem i32 %conv, -256 + ret i32 %rem +} + +define i32 @not_srem_zext_small_divisor(i8 %x) { +; CHECK-LABEL: @not_srem_zext_small_divisor( +; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], -255 +; CHECK-NEXT: ret i32 [[REM]] +; + %conv = zext i8 %x to i32 + %rem = srem i32 %conv, -255 + ret i32 %rem +} + +define i32 @srem_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @srem_dividend_known_smaller_than_pos_divisor_clear_bits( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253 +; CHECK-NEXT: ret i32 [[AND]] +; + %and = and i32 %x, 253 + %rem = srem i32 %and, 254 + ret i32 %rem +} + +define i32 @not_srem_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @not_srem_dividend_known_smaller_than_pos_divisor_clear_bits( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[AND]], 253 +; CHECK-NEXT: ret i32 [[REM]] +; + %and = and i32 %x, 253 + %rem = srem i32 %and, 253 + ret i32 %rem +} + +define i32 @srem_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @srem_dividend_known_smaller_than_neg_divisor_clear_bits( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253 +; CHECK-NEXT: ret i32 [[AND]] +; + %and = and i32 %x, 253 + %rem = srem i32 %and, -254 + ret i32 %rem +} + +define i32 @not_srem_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) { +; CHECK-LABEL: @not_srem_dividend_known_smaller_than_neg_divisor_clear_bits( +; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[AND]], -253 +; CHECK-NEXT: ret i32 [[REM]] +; + %and = and i32 %x, 253 + %rem = srem i32 %and, -253 + ret i32 %rem +} + +define i32 @srem_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @srem_dividend_known_smaller_than_pos_divisor_set_bits( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253 +; CHECK-NEXT: ret i32 [[OR]] +; + %or = or i32 %x, -253 + %rem = srem i32 %or, 254 + ret i32 %rem +} + +define i32 @not_srem_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @not_srem_dividend_known_smaller_than_pos_divisor_set_bits( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[OR]], 253 +; CHECK-NEXT: ret i32 [[REM]] +; + %or = or i32 %x, -253 + %rem = srem i32 %or, 253 + ret i32 %rem +} + +define i32 @srem_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @srem_dividend_known_smaller_than_neg_divisor_set_bits( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253 +; CHECK-NEXT: ret i32 [[OR]] +; + %or = or i32 %x, -253 + %rem = srem i32 %or, -254 + ret i32 %rem +} + +define i32 @not_srem_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) { +; CHECK-LABEL: @not_srem_dividend_known_smaller_than_neg_divisor_set_bits( +; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253 +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[OR]], -253 +; CHECK-NEXT: ret i32 [[REM]] +; + %or = or i32 %x, -253 + %rem = srem i32 %or, -253 + ret i32 %rem +} + +; Make sure that we're handling the minimum signed constant correctly - can't fold this. + +define i16 @sdiv_min_dividend(i8 %x) { +; CHECK-LABEL: @sdiv_min_dividend( +; CHECK-NEXT: [[Z:%.*]] = zext i8 %x to i16 +; CHECK-NEXT: [[D:%.*]] = sdiv i16 -32768, [[Z]] +; CHECK-NEXT: ret i16 [[D]] +; + %z = zext i8 %x to i16 + %d = sdiv i16 -32768, %z + ret i16 %d +} + +; If the quotient is known to not be -32768, then this can fold. + +define i16 @sdiv_min_divisor(i8 %x) { +; CHECK-LABEL: @sdiv_min_divisor( +; CHECK-NEXT: ret i16 0 +; + %z = zext i8 %x to i16 + %d = sdiv i16 %z, -32768 + ret i16 %d +} + diff --git a/llvm/test/Transforms/InstSimplify/simplify-nested-bitcast.ll b/llvm/test/Transforms/InstSimplify/simplify-nested-bitcast.ll new file mode 100644 index 00000000000..b7ee79415a2 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/simplify-nested-bitcast.ll @@ -0,0 +1,54 @@ +; RUN: opt -always-inline -S %s | FileCheck %s +%0 = type { i64, i64, i8 addrspace(1)*, i8 addrspace(1)* } +%__aaa_struct = type { { i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(1)* }, %0, [17 x i8], { i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(1)* }, %0, [18 x i8] } +%struct.__block_descriptor = type { i64, i64 } +%struct.__block_literal_generic = type { i8*, i32, i32, i8*, %struct.__block_descriptor addrspace(1)* } + +@__aaa_struct_ptr = external addrspace(1) global %__aaa_struct +@__aaa_const_init = constant %__aaa_struct { { i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(1)* } { i8** null, i32 1342177280, i32 0, i8* bitcast (i32 (i8 addrspace(4)*, i32 addrspace(1)*)* @bl0_block_invoke to i8*), %struct.__block_descriptor addrspace(1)* bitcast (%0 addrspace(1)* getelementptr inbounds (%__aaa_struct, %__aaa_struct addrspace(1)* @__aaa_struct_ptr, i32 0, i32 1) to %struct.__block_descriptor addrspace(1)*) }, %0 { i64 0, i64 32, i8 addrspace(1)* getelementptr inbounds (%__aaa_struct, %__aaa_struct addrspace(1)* @__aaa_struct_ptr, i32 0, i32 2, i32 0), i8 addrspace(1)* null }, [17 x i8] c"bl0_block_invoke\00", { i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(1)* } { i8** null, i32 1342177280, i32 0, i8* bitcast (i32 (i8 addrspace(4)*, i32 addrspace(1)*)* @__f1_block_invoke to i8*), %struct.__block_descriptor addrspace(1)* bitcast (%0 addrspace(1)* getelementptr inbounds (%__aaa_struct, %__aaa_struct addrspace(1)* @__aaa_struct_ptr, i32 0, i32 4) to %struct.__block_descriptor addrspace(1)*) }, %0 { i64 0, i64 32, i8 addrspace(1)* getelementptr inbounds (%__aaa_struct, %__aaa_struct addrspace(1)* @__aaa_struct_ptr, i32 0, i32 5, i32 0), i8 addrspace(1)* null }, [18 x i8] c"__f1_block_invoke\00" } + +; Function Attrs: alwaysinline norecurse nounwind readonly +define i32 @bl0_block_invoke(i8 addrspace(4)* nocapture readnone, i32 addrspace(1)* nocapture readonly) #0 { +entry: + %2 = load i32, i32 addrspace(1)* %1, align 4 + %mul = shl nsw i32 %2, 1 + ret i32 %mul +} + +; Function Attrs: alwaysinline nounwind +define i32 @f0(i32 addrspace(1)*, i32 (i32 addrspace(1)*) addrspace(4)*) #1 { +entry: + %block.literal = bitcast i32 (i32 addrspace(1)*) addrspace(4)* %1 to %struct.__block_literal_generic addrspace(4)* + %2 = getelementptr inbounds %struct.__block_literal_generic, %struct.__block_literal_generic addrspace(4)* %block.literal, i64 0, i32 3 + %3 = bitcast i32 (i32 addrspace(1)*) addrspace(4)* %1 to i8 addrspace(4)* + %4 = bitcast i8* addrspace(4)* %2 to i32 (i8 addrspace(4)*, i32 addrspace(1)*)* addrspace(4)* + %5 = load i32 (i8 addrspace(4)*, i32 addrspace(1)*)*, i32 (i8 addrspace(4)*, i32 addrspace(1)*)* addrspace(4)* %4, align 8 + %call = tail call i32 %5(i8 addrspace(4)* %3, i32 addrspace(1)* %0) #2 + ret i32 %call +} + +; CHECK-LABEL: define void @f1 +; CHECK: %1 = load i32 (i8 addrspace(4)*, i32 addrspace(1)*)*, i32 (i8 addrspace(4)*, i32 addrspace(1)*)* addrspace(4)* bitcast (i8* addrspace(4)* getelementptr (%__aaa_struct, %__aaa_struct addrspace(4)* addrspacecast (%__aaa_struct addrspace(1)* @__aaa_struct_ptr to %__aaa_struct addrspace(4)*), i64 0, i32 0, i32 3) to i32 (i8 addrspace(4)*, i32 addrspace(1)*)* addrspace(4)*), align 8 + +; Function Attrs: alwaysinline nounwind +define void @f1(i32 addrspace(1)*) #1 { +entry: + %call = tail call i32 @f0(i32 addrspace(1)* %0, i32 (i32 addrspace(1)*) addrspace(4)* addrspacecast (i32 (i32 addrspace(1)*) addrspace(1)* bitcast (%__aaa_struct addrspace(1)* @__aaa_struct_ptr to i32 (i32 addrspace(1)*) addrspace(1)*) to i32 (i32 addrspace(1)*) addrspace(4)*)) #3 + store i32 %call, i32 addrspace(1)* %0, align 4 + %call1 = tail call i32 @f0(i32 addrspace(1)* %0, i32 (i32 addrspace(1)*) addrspace(4)* addrspacecast (i32 (i32 addrspace(1)*) addrspace(1)* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(1)* } addrspace(1)* getelementptr inbounds (%__aaa_struct, %__aaa_struct addrspace(1)* @__aaa_struct_ptr, i32 0, i32 3) to i32 (i32 addrspace(1)*) addrspace(1)*) to i32 (i32 addrspace(1)*) addrspace(4)*)) #3 + store i32 %call1, i32 addrspace(1)* %0, align 4 + ret void +} + +; Function Attrs: alwaysinline norecurse nounwind readonly +define i32 @__f1_block_invoke(i8 addrspace(4)* nocapture readnone, i32 addrspace(1)* nocapture readonly) #0 { +entry: + %2 = load i32, i32 addrspace(1)* %1, align 4 + %add = add nsw i32 %2, 1 + ret i32 %add +} + +attributes #0 = { alwaysinline norecurse nounwind readonly } +attributes #1 = { alwaysinline nounwind } +attributes #2 = { nobuiltin nounwind } +attributes #3 = { nobuiltin } diff --git a/llvm/test/Transforms/InstSimplify/srem.ll b/llvm/test/Transforms/InstSimplify/srem.ll new file mode 100644 index 00000000000..c828d6d53ac --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/srem.ll @@ -0,0 +1,69 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @negated_operand(i32 %x) { +; CHECK-LABEL: @negated_operand( +; CHECK-NEXT: ret i32 0 +; + %negx = sub i32 0, %x + %rem = srem i32 %negx, %x + ret i32 %rem +} + +define <2 x i32> @negated_operand_commute_vec(<2 x i32> %x) { +; CHECK-LABEL: @negated_operand_commute_vec( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %negx = sub <2 x i32> zeroinitializer, %x + %rem = srem <2 x i32> %negx, %x + ret <2 x i32> %rem +} + +define i32 @knownnegation(i32 %x, i32 %y) { +; CHECK-LABEL: @knownnegation( +; CHECK-NEXT: ret i32 0 +; + %xy = sub i32 %x, %y + %yx = sub i32 %y, %x + %rem = srem i32 %xy, %yx + ret i32 %rem +} + +define <2 x i32> @knownnegation_commute_vec(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @knownnegation_commute_vec( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %xy = sub <2 x i32> %x, %y + %yx = sub <2 x i32> %y, %x + %rem = srem <2 x i32> %xy, %yx + ret <2 x i32> %rem +} + +define <3 x i32> @negated_operand_vec_undef(<3 x i32> %x) { +; CHECK-LABEL: @negated_operand_vec_undef( +; CHECK-NEXT: ret <3 x i32> zeroinitializer +; + %negx = sub <3 x i32> <i32 0, i32 undef, i32 0>, %x + %rem = srem <3 x i32> %negx, %x + ret <3 x i32> %rem +} + +define <2 x i32> @negated_operand_vec_nonsplat(<2 x i32> %x) { +; CHECK-LABEL: @negated_operand_vec_nonsplat( +; CHECK-NEXT: [[NEGX:%.*]] = sub <2 x i32> <i32 0, i32 1>, [[X:%.*]] +; CHECK-NEXT: [[REM:%.*]] = srem <2 x i32> [[NEGX]], [[X]] +; CHECK-NEXT: ret <2 x i32> [[REM]] +; + %negx = sub <2 x i32> <i32 0, i32 1>, %x ; not 0, don't fold + %rem = srem <2 x i32> %negx, %x + ret <2 x i32> %rem +} + +define i32 @negated_operand_commute(i32 %x) { +; CHECK-LABEL: @negated_operand_commute( +; CHECK-NEXT: ret i32 0 +; + %negx = sub i32 0, %x + %rem = srem i32 %x, %negx + ret i32 %rem +} diff --git a/llvm/test/Transforms/InstSimplify/sub.ll b/llvm/test/Transforms/InstSimplify/sub.ll new file mode 100644 index 00000000000..4e2064527c4 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/sub.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define i32 @sub_self(i32 %A) { +; CHECK-LABEL: @sub_self( +; CHECK-NEXT: ret i32 0 +; + %B = sub i32 %A, %A + ret i32 %B +} + +define <2 x i32> @sub_self_vec(<2 x i32> %A) { +; CHECK-LABEL: @sub_self_vec( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %B = sub <2 x i32> %A, %A + ret <2 x i32> %B +} + +define i32 @sub_zero(i32 %A) { +; CHECK-LABEL: @sub_zero( +; CHECK-NEXT: ret i32 [[A:%.*]] +; + %B = sub i32 %A, 0 + ret i32 %B +} + +define <2 x i32> @sub_zero_vec(<2 x i32> %A) { +; CHECK-LABEL: @sub_zero_vec( +; CHECK-NEXT: ret <2 x i32> [[A:%.*]] +; + %B = sub <2 x i32> %A, <i32 0, i32 undef> + ret <2 x i32> %B +} + +define i32 @neg_neg(i32 %A) { +; CHECK-LABEL: @neg_neg( +; CHECK-NEXT: ret i32 [[A:%.*]] +; + %B = sub i32 0, %A + %C = sub i32 0, %B + ret i32 %C +} + +define <2 x i32> @neg_neg_vec(<2 x i32> %A) { +; CHECK-LABEL: @neg_neg_vec( +; CHECK-NEXT: ret <2 x i32> [[A:%.*]] +; + %B = sub <2 x i32> <i32 0, i32 undef>, %A + %C = sub <2 x i32> <i32 0, i32 undef>, %B + ret <2 x i32> %C +} + diff --git a/llvm/test/Transforms/InstSimplify/undef.ll b/llvm/test/Transforms/InstSimplify/undef.ll new file mode 100644 index 00000000000..fd16ddc2f94 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/undef.ll @@ -0,0 +1,362 @@ +; RUN: opt -instsimplify -S < %s | FileCheck %s + +define i64 @test0() { +; CHECK-LABEL: @test0( +; CHECK: ret i64 undef +; + %r = mul i64 undef, undef + ret i64 %r +} + +define i64 @test1() { +; CHECK-LABEL: @test1( +; CHECK: ret i64 undef +; + %r = mul i64 3, undef + ret i64 %r +} + +define i64 @test2() { +; CHECK-LABEL: @test2( +; CHECK: ret i64 undef +; + %r = mul i64 undef, 3 + ret i64 %r +} + +define i64 @test3() { +; CHECK-LABEL: @test3( +; CHECK: ret i64 0 +; + %r = mul i64 undef, 6 + ret i64 %r +} + +define i64 @test4() { +; CHECK-LABEL: @test4( +; CHECK: ret i64 0 +; + %r = mul i64 6, undef + ret i64 %r +} + +define i64 @test5() { +; CHECK-LABEL: @test5( +; CHECK: ret i64 undef +; + %r = and i64 undef, undef + ret i64 %r +} + +define i64 @test6() { +; CHECK-LABEL: @test6( +; CHECK: ret i64 undef +; + %r = or i64 undef, undef + ret i64 %r +} + +define i64 @test7() { +; CHECK-LABEL: @test7( +; CHECK: ret i64 undef +; + %r = udiv i64 undef, 1 + ret i64 %r +} + +define i64 @test8() { +; CHECK-LABEL: @test8( +; CHECK: ret i64 undef +; + %r = sdiv i64 undef, 1 + ret i64 %r +} + +define i64 @test9() { +; CHECK-LABEL: @test9( +; CHECK: ret i64 0 +; + %r = urem i64 undef, 1 + ret i64 %r +} + +define i64 @test10() { +; CHECK-LABEL: @test10( +; CHECK: ret i64 0 +; + %r = srem i64 undef, 1 + ret i64 %r +} + +define i64 @test11() { +; CHECK-LABEL: @test11( +; CHECK: ret i64 undef +; + %r = shl i64 undef, undef + ret i64 %r +} + +define i64 @test11b(i64 %a) { +; CHECK-LABEL: @test11b( +; CHECK: ret i64 undef +; + %r = shl i64 %a, undef + ret i64 %r +} + +define i64 @test12() { +; CHECK-LABEL: @test12( +; CHECK: ret i64 undef +; + %r = ashr i64 undef, undef + ret i64 %r +} + +define i64 @test12b(i64 %a) { +; CHECK-LABEL: @test12b( +; CHECK: ret i64 undef +; + %r = ashr i64 %a, undef + ret i64 %r +} + +define i64 @test13() { +; CHECK-LABEL: @test13( +; CHECK: ret i64 undef +; + %r = lshr i64 undef, undef + ret i64 %r +} + +define i64 @test13b(i64 %a) { +; CHECK-LABEL: @test13b( +; CHECK: ret i64 undef +; + %r = lshr i64 %a, undef + ret i64 %r +} + +define i1 @test14() { +; CHECK-LABEL: @test14( +; CHECK: ret i1 undef +; + %r = icmp slt i64 undef, undef + ret i1 %r +} + +define i1 @test15() { +; CHECK-LABEL: @test15( +; CHECK: ret i1 undef +; + %r = icmp ult i64 undef, undef + ret i1 %r +} + +define i64 @test16(i64 %a) { +; CHECK-LABEL: @test16( +; CHECK: ret i64 undef +; + %r = select i1 undef, i64 %a, i64 undef + ret i64 %r +} + +define i64 @test17(i64 %a) { +; CHECK-LABEL: @test17( +; CHECK: ret i64 undef +; + %r = select i1 undef, i64 undef, i64 %a + ret i64 %r +} + +define i64 @test18(i64 %a) { +; CHECK-LABEL: @test18( +; CHECK: [[R:%.*]] = call i64 undef(i64 %a) +; CHECK-NEXT: ret i64 undef +; + %r = call i64 (i64) undef(i64 %a) + ret i64 %r +} + +define <4 x i8> @test19(<4 x i8> %a) { +; CHECK-LABEL: @test19( +; CHECK: ret <4 x i8> undef +; + %b = shl <4 x i8> %a, <i8 8, i8 9, i8 undef, i8 -1> + ret <4 x i8> %b +} + +define i32 @test20(i32 %a) { +; CHECK-LABEL: @test20( +; CHECK: ret i32 undef +; + %b = udiv i32 %a, 0 + ret i32 %b +} + +define <2 x i32> @test20vec(<2 x i32> %a) { +; CHECK-LABEL: @test20vec( +; CHECK-NEXT: ret <2 x i32> undef +; + %b = udiv <2 x i32> %a, zeroinitializer + ret <2 x i32> %b +} + +define i32 @test21(i32 %a) { +; CHECK-LABEL: @test21( +; CHECK: ret i32 undef +; + %b = sdiv i32 %a, 0 + ret i32 %b +} + +define <2 x i32> @test21vec(<2 x i32> %a) { +; CHECK-LABEL: @test21vec( +; CHECK-NEXT: ret <2 x i32> undef +; + %b = sdiv <2 x i32> %a, zeroinitializer + ret <2 x i32> %b +} + +define i32 @test22(i32 %a) { +; CHECK-LABEL: @test22( +; CHECK: ret i32 undef +; + %b = ashr exact i32 undef, %a + ret i32 %b +} + +define i32 @test23(i32 %a) { +; CHECK-LABEL: @test23( +; CHECK: ret i32 undef +; + %b = lshr exact i32 undef, %a + ret i32 %b +} + +define i32 @test24() { +; CHECK-LABEL: @test24( +; CHECK: ret i32 undef +; + %b = udiv i32 undef, 0 + ret i32 %b +} + +define i32 @test25() { +; CHECK-LABEL: @test25( +; CHECK: ret i32 undef +; + %b = lshr i32 0, undef + ret i32 %b +} + +define i32 @test26() { +; CHECK-LABEL: @test26( +; CHECK: ret i32 undef +; + %b = ashr i32 0, undef + ret i32 %b +} + +define i32 @test27() { +; CHECK-LABEL: @test27( +; CHECK: ret i32 undef +; + %b = shl i32 0, undef + ret i32 %b +} + +define i32 @test28(i32 %a) { +; CHECK-LABEL: @test28( +; CHECK: ret i32 undef +; + %b = shl nsw i32 undef, %a + ret i32 %b +} + +define i32 @test29(i32 %a) { +; CHECK-LABEL: @test29( +; CHECK: ret i32 undef +; + %b = shl nuw i32 undef, %a + ret i32 %b +} + +define i32 @test30(i32 %a) { +; CHECK-LABEL: @test30( +; CHECK: ret i32 undef +; + %b = shl nsw nuw i32 undef, %a + ret i32 %b +} + +define i32 @test31(i32 %a) { +; CHECK-LABEL: @test31( +; CHECK: ret i32 0 +; + %b = shl i32 undef, %a + ret i32 %b +} + +define i32 @test32(i32 %a) { +; CHECK-LABEL: @test32( +; CHECK: ret i32 undef +; + %b = shl i32 undef, 0 + ret i32 %b +} + +define i32 @test33(i32 %a) { +; CHECK-LABEL: @test33( +; CHECK: ret i32 undef +; + %b = ashr i32 undef, 0 + ret i32 %b +} + +define i32 @test34(i32 %a) { +; CHECK-LABEL: @test34( +; CHECK: ret i32 undef +; + %b = lshr i32 undef, 0 + ret i32 %b +} + +define i32 @test35(<4 x i32> %V) { +; CHECK-LABEL: @test35( +; CHECK: ret i32 undef +; + %b = extractelement <4 x i32> %V, i32 4 + ret i32 %b +} + +define i32 @test36(i32 %V) { +; CHECK-LABEL: @test36( +; CHECK: ret i32 undef +; + %b = extractelement <4 x i32> undef, i32 %V + ret i32 %b +} + +define i32 @test37() { +; CHECK-LABEL: @test37( +; CHECK: ret i32 undef +; + %b = udiv i32 undef, undef + ret i32 %b +} + +define i32 @test38(i32 %a) { +; CHECK-LABEL: @test38( +; CHECK: ret i32 undef +; + %b = udiv i32 %a, undef + ret i32 %b +} + +define i32 @test39() { +; CHECK-LABEL: @test39( +; CHECK: ret i32 undef +; + %b = udiv i32 0, undef + ret i32 %b +} diff --git a/llvm/test/Transforms/InstSimplify/vec-cmp.ll b/llvm/test/Transforms/InstSimplify/vec-cmp.ll new file mode 100644 index 00000000000..ca6361a18ac --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/vec-cmp.ll @@ -0,0 +1,65 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +define <2 x i1> @nonzero_vec_splat(<2 x i32> %x) { +; CHECK-LABEL: @nonzero_vec_splat( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %y = or <2 x i32> %x, <i32 1, i32 1> + %c = icmp eq <2 x i32> %y, zeroinitializer + ret <2 x i1> %c +} + +define <2 x i1> @nonzero_vec_nonsplat(<2 x i32> %x) { +; CHECK-LABEL: @nonzero_vec_nonsplat( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %y = or <2 x i32> %x, <i32 2, i32 1> + %c = icmp ne <2 x i32> %y, zeroinitializer + ret <2 x i1> %c +} + +define <2 x i1> @nonzero_vec_undef_elt(<2 x i32> %x) { +; CHECK-LABEL: @nonzero_vec_undef_elt( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %y = or <2 x i32> %x, <i32 undef, i32 1> + %c = icmp eq <2 x i32> %y, zeroinitializer + ret <2 x i1> %c +} + +define <2 x i1> @may_be_zero_vec(<2 x i32> %x) { +; CHECK-LABEL: @may_be_zero_vec( +; CHECK-NEXT: [[Y:%.*]] = or <2 x i32> %x, <i32 0, i32 1> +; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[Y]], zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[C]] +; + %y = or <2 x i32> %x, <i32 0, i32 1> + %c = icmp ne <2 x i32> %y, zeroinitializer + ret <2 x i1> %c +} + +; Multiplies of non-zero numbers are non-zero if there is no unsigned overflow. +define <2 x i1> @nonzero_vec_mul_nuw(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @nonzero_vec_mul_nuw( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %xnz = or <2 x i32> %x, <i32 1, i32 2> + %ynz = or <2 x i32> %y, <i32 3, i32 undef> + %m = mul nuw <2 x i32> %xnz, %ynz + %c = icmp eq <2 x i32> %m, zeroinitializer + ret <2 x i1> %c +} + +; Multiplies of non-zero numbers are non-zero if there is no signed overflow. +define <2 x i1> @nonzero_vec_mul_nsw(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @nonzero_vec_mul_nsw( +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> +; + %xnz = or <2 x i32> %x, <i32 undef, i32 2> + %ynz = or <2 x i32> %y, <i32 3, i32 4> + %m = mul nsw <2 x i32> %xnz, %ynz + %c = icmp ne <2 x i32> %m, zeroinitializer + ret <2 x i1> %c +} + diff --git a/llvm/test/Transforms/InstSimplify/vector_gep.ll b/llvm/test/Transforms/InstSimplify/vector_gep.ll new file mode 100644 index 00000000000..42916c4c07a --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/vector_gep.ll @@ -0,0 +1,106 @@ +; RUN: opt -S -instsimplify < %s | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +declare void @helper(<2 x i8*>) +define void @test(<2 x i8*> %a) { + %A = getelementptr i8, <2 x i8*> %a, <2 x i32> <i32 0, i32 0> + call void @helper(<2 x i8*> %A) + ret void +} + +define <4 x i8*> @test1(<4 x i8*> %a) { + %gep = getelementptr i8, <4 x i8*> %a, <4 x i32> zeroinitializer + ret <4 x i8*> %gep + +; CHECK-LABEL: @test1 +; CHECK-NEXT: ret <4 x i8*> %a +} + +define <4 x i8*> @test2(<4 x i8*> %a) { + %gep = getelementptr i8, <4 x i8*> %a + ret <4 x i8*> %gep + +; CHECK-LABEL: @test2 +; CHECK-NEXT: ret <4 x i8*> %a +} + +%struct = type { double, float } + +define <4 x float*> @test3() { + %gep = getelementptr %struct, <4 x %struct*> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>, <4 x i32> <i32 1, i32 1, i32 1, i32 1> + ret <4 x float*> %gep + +; CHECK-LABEL: @test3 +; CHECK-NEXT: ret <4 x float*> undef +} + +%struct.empty = type { } + +define <4 x %struct.empty*> @test4(<4 x %struct.empty*> %a) { + %gep = getelementptr %struct.empty, <4 x %struct.empty*> %a, <4 x i32> <i32 1, i32 1, i32 1, i32 1> + ret <4 x %struct.empty*> %gep + +; CHECK-LABEL: @test4 +; CHECK-NEXT: ret <4 x %struct.empty*> %a +} + +define <4 x i8*> @test5() { + %c = inttoptr <4 x i64> <i64 1, i64 2, i64 3, i64 4> to <4 x i8*> + %gep = getelementptr i8, <4 x i8*> %c, <4 x i32> <i32 1, i32 1, i32 1, i32 1> + ret <4 x i8*> %gep + +; CHECK-LABEL: @test5 +; CHECK-NEXT: ret <4 x i8*> getelementptr (i8, <4 x i8*> <i8* inttoptr (i64 1 to i8*), i8* inttoptr (i64 2 to i8*), i8* inttoptr (i64 3 to i8*), i8* inttoptr (i64 4 to i8*)>, <4 x i64> <i64 1, i64 1, i64 1, i64 1>) +} + +@v = global [24 x [42 x [3 x i32]]] zeroinitializer, align 16 + +define <16 x i32*> @test6() { +; CHECK-LABEL: @test6 +; CHECK-NEXT: ret <16 x i32*> getelementptr inbounds ([24 x [42 x [3 x i32]]], [24 x [42 x [3 x i32]]]* @v, <16 x i64> zeroinitializer, <16 x i64> zeroinitializer, <16 x i64> <i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15>, <16 x i64> zeroinitializer) + %VectorGep = getelementptr [24 x [42 x [3 x i32]]], [24 x [42 x [3 x i32]]]* @v, i64 0, i64 0, <16 x i64> <i64 0, i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i64 9, i64 10, i64 11, i64 12, i64 13, i64 14, i64 15>, i64 0 + ret <16 x i32*> %VectorGep +} + +; PR32697 +; CHECK-LABEL: tinkywinky( +; CHECK-NEXT: ret <4 x i8*> undef +define <4 x i8*> @tinkywinky() { + %patatino = getelementptr i8, i8* undef, <4 x i64> undef + ret <4 x i8*> %patatino +} + +; PR32697 +; CHECK-LABEL: dipsy( +; CHECK-NEXT: ret <4 x i8*> undef +define <4 x i8*> @dipsy() { + %patatino = getelementptr i8, <4 x i8 *> undef, <4 x i64> undef + ret <4 x i8*> %patatino +} + +; PR32697 +; CHECK-LABEL: laalaa( +; CHECK-NEXT: ret <4 x i8*> undef +define <4 x i8*> @laalaa() { + %patatino = getelementptr i8, <4 x i8 *> undef, i64 undef + ret <4 x i8*> %patatino +} + +define <2 x i8*> @zero_index(i8* %p) { +; CHECK-LABEL: @zero_index( +; CHECK-NEXT: %gep = getelementptr i8, i8* %p, <2 x i64> zeroinitializer +; CHECK-NEXT: ret <2 x i8*> %gep +; + %gep = getelementptr i8, i8* %p, <2 x i64> zeroinitializer + ret <2 x i8*> %gep +} + +define <2 x {}*> @unsized({}* %p) { +; CHECK-LABEL: @unsized( +; CHECK-NEXT: %gep = getelementptr {}, {}* %p, <2 x i64> undef +; CHECK-NEXT: ret <2 x {}*> %gep +; + %gep = getelementptr {}, {}* %p, <2 x i64> undef + ret <2 x {}*> %gep +} diff --git a/llvm/test/Transforms/InstSimplify/vector_ptr_bitcast.ll b/llvm/test/Transforms/InstSimplify/vector_ptr_bitcast.ll new file mode 100644 index 00000000000..97c8343bfb9 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/vector_ptr_bitcast.ll @@ -0,0 +1,35 @@ +; RUN: opt -S -instsimplify < %s | FileCheck %s +target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128" + +%mst = type { i8*, i8* } +%mst2 = type { i32*, i32*, i32*, i32* } + +@a = private unnamed_addr constant %mst { i8* inttoptr (i64 -1 to i8*), + i8* inttoptr (i64 -1 to i8*)}, + align 8 +@b = private unnamed_addr constant %mst2 { i32* inttoptr (i64 42 to i32*), + i32* inttoptr (i64 67 to i32*), + i32* inttoptr (i64 33 to i32*), + i32* inttoptr (i64 58 to i32*)}, + align 8 + +define i64 @fn() { + %x = load <2 x i8*>, <2 x i8*>* bitcast (%mst* @a to <2 x i8*>*), align 8 + %b = extractelement <2 x i8*> %x, i32 0 + %c = ptrtoint i8* %b to i64 + ; CHECK-LABEL: @fn + ; CHECK-NEXT: ret i64 -1 + ret i64 %c +} + +define i64 @fn2() { + %x = load <4 x i32*>, <4 x i32*>* bitcast (%mst2* @b to <4 x i32*>*), align 8 + %b = extractelement <4 x i32*> %x, i32 0 + %c = extractelement <4 x i32*> %x, i32 3 + %d = ptrtoint i32* %b to i64 + %e = ptrtoint i32* %c to i64 + %r = add i64 %d, %e + ; CHECK-LABEL: @fn2 + ; CHECK-NEXT: ret i64 100 + ret i64 %r +} |